3 ms·
If your function operates with a pointer to a struct you don't need to put the contents of the struct in the header file. You can simply declare the struct with
by ufo 8y ago
If your function operates with a pointer to a struct you don't need to put the contents of the struct in the header file. You can simply declare the struct with
struct mystruct;
and then use `mystruct*` in the function prototypes. I think in C++ this is known as the PIMPL pattern.
I was also asking more about user-defined libraries than about the standard library...
- frankzinger 8y agoOpaque types do not force you to do the allocation in the library. my_lib.h: struct my_struct; size_t my_struct_size(void); #define MY_STRUCT_MAX_SIZE 512 #define MY_STRUCT_VAR(name) \ char name##_buf__[MY_STRUCT_MAX_SIZE]; \ struct my_struct* name = name##_buf__ void my_construct(struct my_struct*, int, float); my_lib.c: struct my_struct { int i; float f; }; size_t my_struct_size(void) { return sizeof(struct my_struct); } void my_construct(struct my_struct* ms, int i, float f) { ms->i = i; ms->f = f; } user.c: // On the heap struct my_struct* ms = malloc(my_struct_size()); my_construct(ms, 123, 456.0f); // On the stack MY_STRUCT_VAR(ms2); my_construct(ms2, 123, 456.0f);
- ufo 8y agoDo you know of any libraries that do this? When I tried it here GCC complained about `ms2 = ms2_buf__` being an assignment between incompatible pointer types. That sounds like an easy way to get into trouble and undefined behavior.
- frankzinger 8y agoI just wanted to convey the idea so I didn't compile or check the code. But now that you bring up UB, I would change the MY_STRUCT_VAR macro as follows: #define MY_STRUCT_VAR(name) \ _Alignof(max_align_t) \ unsigned char name##_buf__[MY_STRUCT_MAX_SIZE]; \ struct my_struct* name = (struct my_struct*)name##_buf__ Ie, changed to unsigned char and set the buffer to have the maximum (strictest) alignment. And added the cast. It's a pretty widely-used technique and I have satisfied myself in the past that it's not UB (ie, by checking the Standard). I am no language lawyer though so don't take my word for it. The heap example, on the other hand, is pretty much identical to what an allocation inside your library would look like so feel free to disregard the stack example if you'd like. One example of something based on the same principle is the 'sockaddr' structure in the BSD sockets API. See https://en.wikipedia.org/wiki/Type_punning#Sockets_example https://en.wikipedia.org/wiki/Type_punning#Sockets_example.
- frankzinger 8y ago_Alignof(max_align_t) should be _Alignas(max_align_t) or _Alignas(_Alignof(max_align_t))