Conflict Anonymous Declaration in title

EDIT: changed foo_t to foo as a name because POSIX reserves types ending in _t EDIT: changed _foo_s to foo_s because C claims names starting with underscores

I am puzzled that the best way is this:

  • library implementation sees structure elements, but library users do not
  • the compiler checks to see if the function definition in the implementation header matches
  • use c99

My first hit in this is this:

foo.h (protective masks are omitted for brevity):

typedef struct foo_s foo; struct foo_s; foo* foo_create(void); void foo_do_something(foo *foo); 

foo.c:

 #include "foo.h" struct foo_s { /* some_hidden_members */ }; foo* foo_create() { /* allocate memory etc */ } void foo_do_something(foo *foo) { /* do something with foo */ } 

This is similar to gcc. Everyone who includes foo.h sees only an anonymous declarative declaration, and the actual layout of struct foo_s is known only in foo.c

I started to feel something strange with the above when I tried to use include-what-you-use, which clang uses. When I used it to check foo.c , he informed me that foo.h should not contain a direct declaration of struct foo_s . I thought this was a bug in iwyu, because obviously this would not be a problem for anyone who includes foo.h

At this moment, let me come to my second demand from the very beginning. foo.c includes foo.h so that the compiler can verify that every function declared in foo.h corresponds to an implementation in foo.c I think I need this because I too often encountered segmentation errors, because the function signature of my implementation did not match the one in the header that other code used.

Later I tried to compile the code with clang (compiling with -Wall -Wextra -Werror ) and received the following message:

 error: redefinition of typedef 'foo' is a C11 feature 

I don’t want my code to depend on the C11 function, and I want to be sure that the functions in the general header correspond to the implementation. How to solve this?

I see a way to split foo.h into foo.h and foo_private.h :

foo.h (protective masks are omitted for brevity):

 struct foo_s; #include "foo_private.h" 

foo_private.h (protective masks are omitted for brevity):

 typedef struct foo_s foo; foo* foo_create(void); void foo_do_something(foo *foo); 

And then I will include foo_private.h in foo.c and the other code will include foo.h This would mean that foo.c no longer sees the direct declaration of foo_s and thus clang and iwyu should be happy. It also means that the implementation of my functions is checked for compliance with the header.

But while this works, I wonder if this is the best solution, because:

  • Waste seems to have one header file with only two lines
  • I don’t know of other projects that do it this way (and looking at my / usr / include, I don’t see either)

So, what would be the solution that meets the three criteria listed above? Or is it the solution I found to go?

+5
source share
1 answer

Kudos to the noble intention of hiding data!

What about the next one?

foo.h (protective masks are omitted for brevity):

 typedef struct foo_t foo_t; // note change 0 // note change 1 foo_t* foo_create(void); void foo_do_something(foo_t *foo); 

foo.c:

 #include "foo.h" struct foo_t { // note change 2 /* some_hidden_members */ }; foo_t* foo_create() { /* allocate memory etc */ } void foo_do_something(foo_t *foo) { /* do something with foo */ } 
+4
source

Source: https://habr.com/ru/post/1202997/


All Articles