Typedef and Struct in C and H files

I use the following code to create various structures, but I give people outside the C file a pointer to it. (Yes, I know that they could potentially run into it, so this doesn't exactly look like a personal keyword in Java, but it's good with me).

Anyway, I used the following code, and today I watched it, and I am very surprised that it really works, can someone explain why this is?

In my C file, I create my structure but don’t give it a tag in the typedef namespace:

struct LABall { int x; int y; int radius; Vector velocity; }; 

And in file H I put this:

 typedef struct LABall* LABall; 

I obviously use #include "LABall.h" in the c file, but I DO NOT use #include "LABall.c" in the header file, as this will hit the target of a separate header file. So, why can I create a pointer to the LABall * structure in the H file, if I haven't included it at all? Does this have anything to do with the struct namespace working on files, even if one file is in no way related to another?

Thanks.

+6
c include struct typedef
source share
3 answers

Since you are specifying the exact reason why the “why” language works this way, I assume that you want some exact links. If you find that pedant, just skip notes ...

This works because of two things:

  • All pointers to structure types have the same representation (note that this does not apply to all types of pointers, as for standard C). [1] Therefore, the compiler has enough information to create the right code for all uses of your pointer-structure type.

  • The tag namespace (struct, enum, union) is really compatible across all translation units. [2] Thus, the two structures (even if one of them is not fully defined, that is, does not contain the declarations of the participants) are the same.

(BTW, #import is non-standard.)

[1] According to paragraph 1256 §6.2.5.27:

All pointers to structure types must have the same presentation and alignment requirements. Pointers to other types should not have the same presentation or alignment requirements.

[2] According to paragraph 1256 §6.2.7.1:

two structures, unions, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: if declared by a tag, the other is declared with the same tag. If both are complete types, then the following additional requirements apply: [does not concern us].

+7
source share

The standard template for such things is to have a foo.h file that defines an API, for example

 typedef struct _Foo Foo; Foo *foo_new(); void foo_do_something(Foo *foo); 

and foo.c file that provides an implementation for this API, for example

 struct _Foo { int bar; }; Foo *foo_new() { Foo *foo = malloc(sizeof(Foo)); foo->bar = 0; return foo; } void foo_do_something(Foo *foo) { foo->bar++; } 

This hides the entire memory structure and size of the structure in the implementation in foo.c , and the interface opened through foo.h is completely independent of these internal elements: A caller.c , which only #include "foo.h" will only have storing a pointer to something, and pointers are always the same size:

 #include "foo.h" void bleh() { Foo *f = foo_new(); foo_do_something(f); } 

Note. I left the release of memory as an exercise for the reader. :-)

Of course, this means that the following broken.c file will NOT work:

 #include "foo.h" void broken() { Foo f; foo_do_something(&f); } 

since the size of memory needed to actually create a variable of type Foo is not known in this file.

+22
source share

IN

 typedef struct A* B; 

since all pointer interfaces are the same, knowing that B means that the pointer to structure A already contains enough information. The actual implementation of A does not matter (this method is called an "opaque pointer".)

(BTW, it’s better to rename one of LABall . This confuses that the same name is used for incompatible types.)

+1
source share

All Articles