Private members in C structures

May 18, 2008 · Posted in C / C + +

This week, here at work had more proof that programming paradigm is a completely language-independent, ie not by the fact that you're programming in C + +, compiling with g + + your code will be object-oriented so little, if you program in ANSI C your code will necessarily be structured or you will be unable to object-oriented programming.

I'm reading right, Object Orientation in ANSI C?

Yes and no!

Things like inheritance, polymorphism and overloading are complicated to make / emulate in C, but you can program using a style that behaves similarly to object orientation. The libdfb is written in C but "object oriented", so that you create, manipulate to destroy elements that behave very similarly to objects.

Here at work, we have a system of hardware abstraction in C that connects with a GUI in C + +. The lowest layer in C was also written (and very well written, tell by the way) with these techniques, simulating an object orientation. One of these techniques, I was struck by using one of those footnotes of the books of C.

When compiling C code, each symbol is only visible within the compilation unit in which it was declared, unless it is stated again in other units such as extern. Thus, it is possible to "hide" certain symbols within the compilation unit, making them inaccessible to the outside world. We have with this package.

A compilation unit is the set of files that after pre-processed and compiled generate a single code object. Basically (but not exactly), we can take as each compilation unit implementation file source code (*. c, *. cpp. Etc). Further details on the steps of compiling C and C + + can be found on the blog Caloni.

Using this information, we can create a struct in ANSI C in which its internal members are "private". The magic is in the definition of trap members within the compilation unit and create access methods for these members. For this we use the footnotes that show us the difference between declaration and definition of elements in C:

Declaration or manifesto: the compiler presents an identifier without saying much about its meaning, or tell the compiler that the identifier is XXX, but little is known about what he represents.
Eg

  a ; extern int a;
 void ) ; void blah (void);
 struct st_date; 

Definition and implementation: Tells the compiler that the identifier is determined, such as how much memory should be allocated to it and what the memory address where we can find it, among other things.
Eg

  int a;
 void ) { /* Do anything. void blah (void) (/ * Do anything.  * /)
 /* Some members. st_date struct (/ * Some members.  * /) 

When we speak of structures and types, without setting the compiler has no way to allocate memory for them because nothing is known about how much space a variable of that type need. On the other hand, sometimes without the declaration, the linker can not know that that symbol exists.

When we declare a structure in a header, usually we also define its members there and every time we add this header to a source of ours, we included in the compilation unit as the source of that statement as the definition of this structure, making the members of the public interinstitutionalcollaboration to this compilation unit. This allows us to access its members directly.

If we separate the statement of the definition, only symbol that represents the structure available, but not its members. Thus, any attempt to direct access to a member, will generate a compilation error. An interesting side effect is that as the compiler knows nothing about the size of the structure, you can not directly set a variable of the structure, only a pointer to it, because pointers are all the same size and the compiler only needs the name of the symbol type to create the pointer.

Then we have the header mytype.h something like this:

  # ifndef MY_TYPE_H
 # define MY_TYPE_H

 / * The typedef is not just to keep repeating the word struct.  * /
 / * The statement is only the words: * /
 / * Struct _MYTYPE * /
 typedef struct _MYTYPE my_type;

 my_type ** ) ; void create_my_type (my_type **);
 my_type ** ) ; void destroy_my_type (my_type **);

 my_type * , int ) ; void set_data (my_type *, int);
 my_type * ) ; int get_data (my_type *);
 my_type * , const char * ) ; void set_text (my_type *, const char *);
 get_text ( my_type * ) ; char * get_text (my_type *);

 # endif 

Implementation mytype.c:

  # include "mytype.h"

 # include <stdio.h>
 # include <stdlib.h>
 # include <string.h>

 /* Aqui fica a definição da estrtura. _MYTYPE struct (/ * Here is the definition of estrtura.  * /
     /* Somente depois disso é que o com-  */ int data; / * Only after that, with-* /
     21 ] ; /* pilador vai saber como alocá-la. int text [21], / * pilador will know how to allocate it.  * /
 /* Tente um sizeof(my_type) no main. ), / * Try a sizeof (my_type) in the main.  * /

 my_type ** my_ptr ) { /* some code... void create_my_type (my_type ** my_ptr) (/ * some code ...  * /)
 my_type ** my_ptr ) { /* some code... void destroy_my_type (my_type ** my_ptr) (/ * some code ...  * /)
 my_type * my_ptr , int d ) { /* some code... void set_data (my_type * my_ptr, int d) (/ * some code ...  * /)
 my_type * my_ptr ) { /* some code... int get_data (my_type * my_ptr) (/ * some code ...  * /)
 my_type * my_ptr , const char * text ) { /* some code... void set_text (my_type * my_ptr, const char * text) (/ * some code ...  * /)
 get_text ( my_type * my_ptr ) { /* some code... char * get_text (my_type * my_ptr) (/ * some code ...  * /) 

The complete source code example can be found here.

Because you can not directly create variables of this type, we define a "builder" and a "destructor".

Attempts to direct access to members generate compilation error:

  private-struct-members$ gcc -o teste mytype.h mytype.c main.c user @ host: ~ / private-struct-members $ gcc-o test main.c mytype.h mytype.c
 main.c: In function 'main':
 main.c: 22: error: dereferencing pointer to incomplete type
 private-struct-members$ user @ host: ~ / private-struct-members $ 

Thus, with a little creativity and with the concepts of both the language and the paradigms, it is possible to implement codes really interesting. In this silly example might not have been clear the usefulness of forcing an emulation package or the use of constructor / destructor in C, but in systems where the circumstances do not allow a C + +, or the complexity tends to reach critical levels, such techniques show of great value. In our case, this technique specifically allowed an experienced programmer, did not do the whole project, he discovered that his attempt to direct access to a member of a structure, was contextually inappropriate. Without it, a bug cabuloso logic would appear only at runtime, making the software probably explode in the face of the customer.

Useful links (or not ...):
http://www.directfb.org
http://www.caloni.com.br
http://www.numaboa.com.br/informatica/c/
Paper Development Linux Kernel

Comments

7 Responses to "Private members in C structures"

  1. Diogo V. Kersting on June 10th, 2008 16:40
  2. blab on June 10th, 2008 23:12

    Good night,

    Thank you for your attention.

    I've been changing the blog server and some links ended up being broken. I will resolve it.

    Hugs

  3. blab on June 10th, 2008 23:58

    As promised, right there

    Hugs

  4. blab on June 11th, 2008 00:00
  5. Rodrigo Martins (Warlock) on July 15th, 2008 01:30

    It's time to post something new huh AHHuahuAHUahuA

  6. blab on July 15th, 2008 09:09

    Witch Yes, you're right, but tá osso ...

    Fortunately, I have something in the oven :)

    Hugs

  7. Carcara on October 27th, 2008 13:14

    You can also hide functions external compilation units declaring them with static - This is also true for global variables. Thus the external drive will not know the existence and function static prevent its being declared as extern in another file.

Leave a Reply




Powered by WP Hashcash