I have a function that accepts void* as parameter, but I want to use it as if it's a struct.
typedef struct struct1
{
int val;
} struct2;
void func1(void* struct3)
{
printf("%d",struct3->val);
}
My purpose is for example, if I have a .h file where the function is defined as
typedef void* parameter1;
void func1(parameter1 p1);
And I wants to use the struct as a parameter in that function, without declaring the struct in the .h file.
Thanks for the answer printf("%d",((struct2 *)struct3)->val) mentioned by #i486, that's what I was looking for.
In the header, declare the structure type as an incomplete type. For example:
typedef struct struct1 struct1;
extern void func1(struct1 *p1);
Or:
struct struct1;
void func1(struct struct1 *p1);
You can mix'n'match extern or not and typedef vs struct tag.
In the implementation code (or implementation header if you have multiple source files implementing the support for the type), you include the public header and define the structure type:
struct struct1
{
…private details…
};
In C11 and beyond, you can repeat a typedef as long as it refers to the same type; in earlier versions of C, you could not do that.
The advantage of this approach is that the client code is forced to use your functions because they don't know the internals of the structure, but they get a measure of type safety. In particular, a random structure pointer can't be passed to this function. If everything takes void *, then you can pass a wrong structure type to the function because all void pointers look alike. That's both unkind and unnecessary.
Related
Below code is to implement vtable.
In the below code,
struct A;
typedef struct {
void (*A)(struct A*);
void (*update)(struct A*);
int (*access)(struct A*);
} A_functable;
typedef struct A{
int a;
A_functable *vmt;
} A;
I could not understand mentioning (*A) as function pointer in void (*A)(struct A*); that is member in A_functable, where A is
typedef struct A{
int a;
A_functable *vmt;
} A;
How to understand this syntax?
In
void (*A)(struct A*);
, the first A does not refer to typedef struct A { ... } A as that is only defined further below. At this point the compiler doesn't know anything about a type called A. A is simply the name of the struct member, just like update and access.
(struct A does refer to the struct, however: There's a struct A; declaration further up.)
They are in different namespaces.
In C there are four different namespaces
Tags for a struct/union/enum
Members of struct/union (actually a separate namespace is assigned to each struct/union)
Labels
Ordinary identifiers.
(Section 6.1.2.3 of C90)
Identifiers in different namespaces will not clash with one other and will be referred as separate entities.
So, in your case,
The member of the structure, (*A) being a function pointer is in the second namespace.
The tags for the struct typedef struct A is in the first namespace,
The struct type being an ordinary identifier is in the fourth namespace.
Additionally, the function type for the function pointer (*A)(struct A*) is in the fourth namespace, being an ordinary type.
trying to do object orientation in C, but I don't get it.
I want to have a struct with references to functions and itself. I have this before main, but the compiler complains. How do I work around it?
Compiler complains about:
"Initializer element is not constant", "unknown typename SENSOR_OBJECT"
void config_time_base(alt_u32, void*);
void init_measurement(QUEUE *q);
void read_accelerometerX(QUEUE *q);
void update(QUEUE *q);
typedef struct SENSOR_CLASS
{
char description[80];
alt_u32 x_origo;
alt_u32 y_origo;
alt_u32 time_base;
QUEUE queue;
QUEUE *q;
void (*configure_time_base)(alt_u32, SENSOR_OBJECT*);
void (*reset_samples_vector)(QUEUE*);
void (*read_sensor)(QUEUE*);
void (*update_graph)(QUEUE*);
SENSOR_OBJECT* this;
}SENSOR_OBJECT;
QUEUE q1,q2,q3,q4,q5;
QUEUE* q11 = &q1;
SENSOR_OBJECT accelorometerX =
{ "Accelerometer x",
50, 50,1,q1,q11,
config_time_base,
init_measurement,
read_accelerometerX,
update,
&accelorometerX
};
You have a mention of SENSOR_OBJECT before SENSOR_OBJECT is actually defined:
void (*configure_time_base)(alt_u32, SENSOR_OBJECT*); // <--- mentioned here
SENSOR_OBJECT* this; // <--- mentioned here
}SENSOR_OBJECT; // <--- defined here
This is not allowed.
The easiest way out is to separate the typedef and the struct definition:
typedef struct SENSOR_CLASS SENSOR_OBJECT;
struct SENSOR_CLASS { ...
The Initializer element is not constant error tells you you cannot initialize a field with a thing which is not a constant expression. In order to fix this, write a function that allocates a SENSOR_OBJECT and assigns (not initializes) its fields from the function parameters. This would be your implementation of a constructor.
On a tangentially related note, it doesn't make much sense to keep a this pointer in each object. In order to access this, you would have to know the address of the object, but that address always equals this.
On a less related note, keeping function pointers in the struct is somewhat a waste of memory. Consider keeping them in a separate vtable object (one per class) and having a pointer to that vtable in each instance of the class.
You are using the typedef while defining the type. At the place you use the type alias, the compiler don't know it so replace with:
struct SENSOR_CLASS *this;
or you can make a forward declaration of your type, like:
typedef struct SENSOR_CLASS SENSOR_OBJECT;
struct SENSOR_CLASS {
SENSOR_OBJECT *this;
};
We all know how to declare a structure in C:
struct Label1{ /* variables */ } Label2; // As I learned
But I want to know why this code works without declaring 'struct name':
typedef struct name s_name;
Or is in fact, does typing the code
struct name;
mean that I declared 'struct name' as a void structure or something like this?
Example of code:
typedef struct Data Data;
struct Data{ /*variables*/ };
If in the first line struct Data is declared as a void one, then in the second it's like I'm redeclaring it with members.
What is the explanation for this point?
Something like:
struct MyStruct;
Is called a forward reference. It creates an incomplete type and tells the compiler there will be a type of that name (and it's a struct - it works likewise for unions), and the details "follow later". Of such a type you cannot define variables, until you complete the type.
typedef struct MyStruct MyType;
Will just define the type name to be that struct. This is still an incomplete type.
However, you can take a pointer to an incomplete type:
MyType *my_t_pointer;
struct MyStruct *my_s_pointer;
This is useful for a struct to have pointers to objects of the same type when you provide the full declaration, "completing" the type:
struct MyStruct {
struct MyStruct *next;
};
Actually this is the only way to create nodes for lists, trees, and all other recursive data-structures. This is a major part of C programs (sometimes hidden).
Also, this mechanism is used to hide implementation details. Functions in the header need only know the struct exists to take/pass pointers to it. The use of these functions need not to know the details of the struct (but this way it cannot allocate it, so the module has to cover all aspects which need to know details on the struct). The full declaration is only inside the implementation file of the module.
These pointers are called "opaque" as one cannot "look through", i.e. access the fields of the struct as they are simply not known to it.
my_module.h:
struct MyStruct;
extern void my_init(struct MyStruct *obj);
my_module.c:
struct MyStruct {
int f1;
...
};
my_init(struct MyStruct *obj)
{
...
}
The typedef declares s_name as an alias for struct name so that you can declare variables, e.g.:
s_name *sptr;
The line
struct name;
declares that there is a struct type called name without defining its content. This is usually done in order to be able to declare variables as pointers to the struct type. You cannot declare variables of the actual struct type until it has been defined.
Isn't forward declaration, whether for structures or functions, supposed to do what forward declaration is expected to do, ie, to let us use the structure or function before they are defined? Why is the forward declaration of a structure not working in my code? And the main thing that just misses me, is forward declaration of structures of any use in C at all? When is it used? Can you please give me a small C program example to illustrate this?
My program gives the error error: storage size of 'x' isn't known|.
#include<stdio.h>
struct test;
int main(void)
{
struct test x;
printf("%zu",sizeof(x)); //Gives Error
//printf("%zu",sizeof(struct test));//This fails too
}
struct test
{
int a;
char b;
};
New Edit I tried to do what Carl Noum said,but even this is not working:
#include<stdio.h>
struct test;
void foo(struct test*);
int main(void)
{
struct test x={53,'x'},*ptr=&x;
foo(ptr);
}
void foo(struct test* p)
{
printf("%d,%c",p->a,p->b);
}
struct test
{
int a;
char b;
};
The compiler has to know the struct's layout when it compiles the main function.
A forward declaration is useful if you only have a pointer but not the actual type.
For example if you have a struct that contains a pointer to another struct
struct foo {
struct bar *b;
...
};
It is also essential if the bar also contain foo like
struct bar;
struct foo {
struct bar *b;
};
struct bar {
struct foo f;
};
In this case you have to have bar pre-declared.
A forward declaration usually means that you don't have to include .h file inside other .h file. This can speed up compilation significantly if the .h file is big.
Functions yes, structures no. struct test is an incomplete type where you use it.
A common use case for incomplete types is to declare an opaque type. In a header file, you declare:
struct test;
And then some API that uses struct test only via pointers:
int func1(struct test *);
struct test *func2(void);
In the accompanying implementation, you include the full declaration so that your functions know what to do with the structure:
struct test
{
int a;
char b;
};
void func1(struct test *t)
{
return t->a;
}
Edit:
Your new code doesn't do anything differently - you're still trying to operate on an incomplete type, and you still can't do that. In particular, this declaration:
struct test x = {53,'x'};
Can't work if struct test is an incomplete type. You can (generally) only use pointers to an incomplete type. In this case, that might mean creating a function that allocates and returns a pointer to a new structure, rather than trying to declare and initialize one on the stack.
Struct type declared by a forward declaration (i.e. an incomplete type) can be used only in a limited number of ways. Applying sizeof to such a truct type is not one of them. On top of that, you can't use incomplete types in object definitions and you cannot access data fields of incomplete struct types.
In other words, sizeof requires a complete type. Your forward-declared struct type is not a complete type. Operator -> also requres a complete type of the left-hand side. Object definition (like struct test x) also requires a complete type.
How can I pass around pointers to structs which have private definitions, without prepending the pointer types with struct?
For example this works:
typedef struct Handle {
Ino ino;
} Handle;
bool handle_open(Handle **);
But if I move the struct definition into a source file, other source files are forced to use struct Handle *, instead of Handle *.
You can typedef struct Handle Handle;. In this case, Handle is an incomplete type (just like struct Handle).
This should go fine in a header:
struct _Handle;
typedef struct _Handle Handle;
Then you can put the actual definition of _Handle in the body of the file that actually manipulates the struct.
if I move the struct definition into a source file, other source files are forced to use struct Handle *, instead of Handle *
Then typedef the pointer, instead of (or in addition to) the struct.