I'm working on a header file that declares some opaque structs which is supposed to be defined in the corresponding C file. Here it is:
decl.h
#ifndef DECL_H
#define DECL_H
typedef struct test_t test;
#endif //
Some library that is supposed to be used in the implementation defines another opaque struct in its header lib.h:
//...
typedef struct _library_struct_t library_struct;
//...
Now in my decl.c file I want to make struct test_t to be the same (or compatible) with the library_struct. I tried this:
decl.c
//...
typedef library_struct test; //error: conflicting types for ‘test’
//...
But it does not compile. So the only way to go I can see now is
struct test_t{
library_struct *lib_struct_ptr;
};
Is there shorter or more convenient way? Both test and library_struct are opaque. Why can't I make the test to be the same as library_struct? Can macros be helpful here?
your code is equivalent to
typedef struct test_t test; /* from decl.h */
typedef library_struct test; /* in decl.c */
So you redefine test and of course the compiler doesn't accept that
I don't know what you expect to do through macros but redefinition is not allowed.
In the worst case you can hide the type of a pointer with a void * then casting to the type you (hope) have, but this is obviously dangerous because the compiler will follow you at your own risk.
The compiler does not check the types against you but to help you to see your errors at compile time ...
Related
I have declared a typedef struct on header files as follows:
myheader.h
typedef struct mystruct mystruct;
myheader.c
typedef struct mystruct{
double *ptr1;
double *ptr2;
int *ptr3;
mystruct *ptr4;
mystruct *ptr5;
}mystruct;
program.c
#include "myheader.h"
int main()
{
mystruct *A = (mystruct *)malloc(sizeof(mystruct));
}
when i try to compile using:
gcc -o myprogram myprogram.c myheader.c
i get the following error:
error: invalid application of ‘sizeof’ to incomplete type ‘mystruct’ {aka ‘struct mystruct’}
mystruct * A = (mystruct *)malloc(sizeof(mystruct));
Is there something wrong with my code or am I compiling in the wrong way?
As #someprogrammerdude has already pointed out in his comment about translation units: when the compiler compiles main.c it has only knowledge about main.c and the included headers. So all it knows is that that there is a struct typedefed as mystruct but it knows nothing about its content and thus cannot determine ts size either, so you cannot use sizeof(). For the same reason you couldn't access any struct members, int *p = mystruct->ptr3; or mystruct->ptr1 = &mydouble; wouldn't compile as well.
Nevertheless that design is quite common. Let's assume you want to encapsulate every access to mystruct in an OO like manner. Then you have a source, say mystruct.c where you actually define the structure (like you did in myheader.c) and provide all neccessary getter and setter functions (including an allocation function). Then in every other source you could pass struct pointers any way you like but for everything else you have to use the designated functions.
The advantage of that approach is that in the future you're free to modify the struct whithout having to recompile every source that uses it.
I'm new to C programming and trying to write a simple example. Percisely I tried to abstract over a type implementation and simply use typedef and specify operations I can do with this type. I understand that at that point the type is incomplete, but I was intended to complete it into c-file, not header. Here is it:
test.h
#ifndef _TEST_H
#define _TEST_H
typedef my_type_t;
void init(my_type_t **t);
#endif //_TEST_H
test.c
#include <stdlib.h>
#include "test.h"
// implementation details
struct my_type_t{ //<---- completening my_type_t to be a struct with 1 field
int field;
};
void init(struct my_type_t **t){ //<--- error: conflicting type for init
*t = malloc(sizeof(struct my_type_t));
(*t) -> field = 42;
}
Is something like this possible? I wanted the implementation completely hide all the details about the actual type definition exposing only operations that can be done with it.
UPD: If we rewrite the c-file as follows:
#include <stdlib.h>
#include "test.h"
struct internal_my_type_definition_t{
int field;
};
void init(my_type_t **t){
struct internal_my_type_definition_t *st = malloc(sizeof(struct internal_my_type_definition_t));
st -> field = 42;
*t = st;
}
Is there any problem with such an implementation?
In your header, change
typedef my_type_t;
to
struct my_type_t;
It's a pretty common pattern. Just keep in mind that you'll need a function to allocate the struct on the heap and free it; one of the pieces of information you're hiding is the size of the struct, so the API consumer can really only deal with pointers to the struct not the struct itself.
The idiomatic API would be something like
struct my_type_t* my_type_new(void);
void my_type_free(struct my_type_t* self);
my_type_init would typically be used to initialize an already allocated instance, which is really only useful if you want to chain up to it in the *_new function of a subtype.
Edit: in response to your follow-up question, you could conceivably do something like this in your header:
#if !defined(MY_TYPE_NS)
# define MY_TYPE_NS struct
#endif
typedef MY_TYPE_NS my_type_t my_type;
my_type* my_type_new(void);
/* ... */
Then, in your *.c file:
#define MY_TYPE_NS union
#include "test.h"
union my_type_t {
/* ... */
};
my_type* my_type_new(void*) {
my_type* res = malloc(sizeof(my_type));
res->field = 42;
return res;
}
Which I find to be only slightly evil. I'd probably just use a union nested inside of the struct to avoid any surprises in the code.
The design pattern you are looking for is called "opaque type"/"opaque pointers".
You almost have it correctly, you just need to specify the type explicitly in the header:
typedef struct my_type_t my_type_t;
This is both a typedef and a forward declaration of an incomplete type, which is completed in your .c file and not visible to the caller.
Now the caller can declare pointers to this type, but not objects. They can't access struct members - we've achieved private encapsulation. You have to design your functions to always take a pointer type.
I am creating an interface structure
typedef struct Circular_Buffer_Interface_t * Circular_Buffer_Interface;
typedef struct Circular_Buffer_Interface_t {
U8 (*Put)(Circular_Buffer, void*);
U8 (*Get)(Circular_Buffer, void*);
U8 (*Reset)(Circular_Buffer);
BOOL (*isFull)(Circular_Buffer);
BOOL (*isEmpty)(Circular_Buffer);
} Circular_Buffer_Interface_t;
typedef struct Circular_Buffer_t * Circular_Buffer;
typedef struct Circular_Buffer_t {
Circular_Buffer_Interface Interface;
} Circular_Buffer_t;
My question is when I try to compile why using void* as a function argument it throws a syntax error.
if I use a typedef
typedef void* VoidPtr
and then use
typedef void* VoidPtr;
typedef struct Circular_Buffer_Interface_t {
U8 (*Put)(Circular_Buffer, VoidPtr);
U8 (*Get)(Circular_Buffer, VoidPtr);
U8 (*Reset)(Circular_Buffer);
BOOL (*isFull)(Circular_Buffer);
BOOL (*isEmpty)(Circular_Buffer);
} Circular_Buffer_Interface_t;
everything complies just fine.
Does anyone have a clue while this is happening?
Thanks in advance.
This member declaration
U8 (*Put)(Circular_Buffer, VoidPtr);
will work fine if neither Circular_Buffer nor VoidPtr are defined with typedef at that point in the source code. (U8 must be defined, though.) That's because it will be accepted as a K&R-style function declaration which specifies the names of the parameters but not their types. (That is, Put will be declared as a pointer to a function taking two parameters of unspecified type.)
It will also work if both Circular_Buffer and VoidPtr are defined as typedefs, in which case it will be treated as a normal standard C declaration.
If you compile with -Wall, the first case will probably produce a warning. -Wall is always recommended.
It should fail to compile if only one of the two identifiers is declared as a typedef, so I don't know how it works in the case where typedef void* VoidPtr comes before the member declaration, and typedef struct ... Circular_Buffer comes afterwards. Perhaps that's an obscure feature of an old version of gcc. (Once the compiler decides it is a K&R function declaration, the actual parameter names can be ignored unless the it is a function definition, and in the context in which the line appears, it cannot be a function definition.)
The first declaration, with the void *, seems perfectly valid C. I added some code to make this a complete program:
#include <stdio.h>
typedef int U8;
typedef int BOOL;
typedef int Circular_Buffer;
typedef struct Circular_Buffer_Interface_t {
U8 (*Put)(Circular_Buffer, void*);
U8 (*Get)(Circular_Buffer, void*);
U8 (*Reset)(Circular_Buffer);
BOOL (*isFull)(Circular_Buffer);
BOOL (*isEmpty)(Circular_Buffer);
} Circular_Buffer_Interface_t;
int main() {
puts("hello");
}
This program compiles successfully and without warning with GNU C version 5.2 on MacOSX:
> gcc-5 -std=c99 -Wall x.c
> ./a.out
hello
The same works with the Apple version of clang. Thus I suspect that the problem is with your C compiler, rather than with your code.
I am not trying to have two different structs with the same name, but rather defining the same exact struct two different times (probably in different header files).
For example:
struct foo {
int bar;
};
struct foo {
int bar;
};
gives an error.
The way to do this is to surround your struct with preprocessor instructions
#ifndef STRUCT_FOO
#define STRUCT_FOO
struct foo {
int bar;
};
#endif /* STRUCT_FOO */
#ifndef STRUCT_FOO
#define STRUCT_FOO
struct foo {
int bar;
};
#endif /* STRUCT_FOO */
this has the effect of only defining struct foo once. In combination with the commonly accepted practice of putting such an item in a file called foo.h, like so
#ifndef INCLUDE_FOO_H
#define INCLUDE_FOO_H
struct foo {
int bar;
};
#endif /* INCLUDE_FOO_H */
it also protects against a person doing
#include "foo.h"
#include "foo.h"
(rest of code)
As far as redefining the struct, that is not permitted in the C language; however, you can do some things that approximate a non-full redefine. I recommend avoiding them, as they tend to only make the code more obscure and difficult to maintain.
No.
There is absolutely no point in doing this. If you have a structure that is to be used by multiple compilation units, put it in a .h header file, and #include it from those .c files. Or, if you need it in multiple header files, just include the common header file from those.
Now if you don't need the actual structure definition, but rather just need to declare that it exists (so you can create pointers to said struture), you can use a forward declaration:
struct foo; // defined elsewhere
void somefunc(struct foo *ptr);
Short answer: No
The compiler isn't that smart - you already have struct foo, so you can't have another struct foo even if you think it is the same as the first one.
No.
You should seperate the struct in another header, it sounds like you may be organizing your code poorly and should rethink the design.
You could use a ifndef:
#ifndef NAMEDEF
struct name {
int val;
};
#define NAMEDEF
#endif
Although, I must reiterate that you need to rethink how your header files are designed and put this struct in a common header.
Its also possible to use a foreward declaration:
struct name;
void function() {
}
I want to declare a structure value in a different structure definition in header file. So I have done the following in header file. But compiler gives me the error message field myStructMember has incomplete type
in A.h header file:
struct My_A{
int value;
};
In B.h header file:
struct My_A; // forward declaration
struct My_B
{
struct My_A myStructMember; // error is here!
int differentValue;
};
Is it possible to declare a struct member within a structure declarations?
EDIT: My_A and My_B are declarated in different header file.
EDIT 2:
When I add include "A.h" in B.h, then it works. Does it make any problem?
In B.h header file:
include "A.h" // added this line insead of forward declaration
struct My_B
{
struct My_A myStructMember; // not any error anymore
int differentValue;
};
Not without # including A.h in B.h (or before B.h every time it is referenced - when the compiler parses My_B otherwise it lacks the information required to determine the size of My_A. You could use a pointer instead, but that gains all the overhead of handling them.
If you are just trying to achieve abstraction / details hiding, then you could change your forward declaration of My_A so that it is now a struct of the correct size (using a char array, for instance). Then you must make sure that nothing includes both A.h and B.h as that will cause a compiler error. Oh, and really make sure you get the size right or weird stuff will happen. There are ways to ensure this is correct using macro assertions.
e.g. make B.h
struct My_A{
char hidden_data[4];
};
struct My_B
{
struct My_A myStructMember;
int differentValue;
};
The error is what it says - you can't use struct until you has it's complete type. You simply don't know its size at that point. Forward declaration won't help here.
Alternatively you can use pointer to struct. Pointer size is known.