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;
};
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.
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.
I am using MinGW on Windows. I am building linked list and I am confused with this.
#include <stdio.h>
#include <stdlib.h>
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
int main(void)
{
List item;
List * head;
head = NULL;
return 0;
}
I now that struct can't have struct variable(object, instance of that struct), but can have pointer of that struct type. Didn't know that pointer can be pointer of unexisting type. struct BlaBla * next;(not for linked list, it must be struct Data * next but mean general talking)
Yes, you can, because then the compiler, upon encountering the unknown type name for the first time, assumes that there's somehwere a struct type definition with this name. Then it will forward-declare the struct name for you, let you use it as a pointer, but you can't dereference it nor can you do pointer arithmetic on it (since it's an incomplete type).
The compiler will accept code such as your example:
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
This is okay because the size of pointers is known to the compiler, and the compiler is assuming that the struct will be defined before it is dereferenced.
Because the compiler acts this way, it's possible to do this:
typedef struct Data
{
int x;
int y;
struct Data * next; /* points to itself */
} List;
However, if you were to include the struct inline, like this:
typedef struct Data
{
int x;
int y;
struct BlaBla blaStruct; /* Not a pointer. Won't compile. */
}List;
The compiler can't work out how big struct Data is because it doesn't know how big struct BlaBla is. To get this to compile, you need to include the definition of struct BlaBla.
Note that, as soon as you need to access the members of struct BlaBla, you will need to include the header file that defines it.
It depends on what you mean by "unexisting". If you haven't even declared BlaBla, you'll get an error.
If you've declared it but not yet defined it, that will work fine. You're allowed to have pointers to incomplete types.
In fact, that's the normal way of doing opaque pointers in C.
So, you might think that this is invalid because there's no declaration of struct BlaBla in scope:
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
However, it's actually okay since it's both declaring struct BlaBla and defining next at the same time.
Of course, since definition implies declaration, this is also okay:
struct BlaBla { int xyzzy; };
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
In order to declare a variable or field of a given type, pass one as a parameter, or copy one to another of the same type, the compiler has to know how many bytes the variable or field occupies, what alignment requirements it has (if any), and what other pointer types it's compatible with, but that's all the compiler needs to know about it. In all common dialects of C, a pointer to any structure will always be the same size and require the same alignment, regardless of the size of the structure to which it points or what that structure may contain, and pointers to any structure type are only compatible with other pointers to the same structure type.
Consequently, code which doesn't need to do anything with pointers to a structure except allocate space to hold the pointers themselves [as opposed to the structures at which they point], pass them as parameters, or copy them to other pointers, doesn't need to know anything about the structure type to which they point beyond its unique name. Code which needs to allocate space for a structure (as opposed to a pointer to one) or access any of its members must know more about its type, but code which doesn't do those things doesn't need such information.
Suppose I have this in list.h:
typedef struct list_t list_t;
typedef struct list_iter_t list_iter_t;
list_iter_t iterator(list_t *list);
and then define them in list.c:
typedef struct node_t {
...
} node_t;
struct list_iter_t {
node_t *current;
// this contains info on whether the iterator has reached the end, etc.
char danger;
};
struct list_t {
...
}
list_iter_t iterator(list_t *list) {
list_iter_t iter;
...
return iter;
}
Is there anything I can do aside from including the struct declaration in the header file so that in some file test.c I can have:
#include "list.h"
void foo(list_t *list) {
list_iter_t = iterator(list);
...
}
Like maybe tell the compiler the storage size of list_iter_t somehow? It's inconvenient to have to use a pointer (not because it's a pointer, but for other reasons), but at the same time I would like to hide the implementation details as much as possible.
The succinct answer is "No".
The way you tell the compiler the size of a struct is by telling it the details of how the struct is structured. If you want to allocate an object, rather than a pointer to the object, the compiler must know the complete type of the object. You also can't access the members of a structure via a pointer to the structure if the type is incomplete. That is, the compiler must know the offset and type of the member to generate the correct code to access someptr->member (as well as to allocate somevalue or access somevalue.member).
It is possible to tell the compiler the size of the structure, using a dummy definition like:
struct node_t {
char dummy[sizeof(struct { ... })];
};
(with the proper definition instead available to the implementation file).
Formally this causes undefined behaviour; it is likely to somewhat work in practice, though.
You are probably best off just including the proper structure definition though, and leaving a comment to the effect that code should simply not touch the internal members.
What is forward reference in C with respect to pointers?
Can I get an example?
See this page on forward references. I don't see how forward referencing would be different with pointers and with other PoD types.
Note that you can forward declare types, and declare variables which are pointers to that type:
struct MyStruct;
struct MyStruct *ptr;
struct MyStruct var; // ILLEGAL
ptr->member; // ILLEGAL
struct MyStruct {
// ...
};
// Or:
typedef struct MyStruct MyStruct;
MyStruct *ptr;
MyStruct var; // ILLEGAL
ptr->member; // ILLEGAL
struct MyStruct {
// ...
};
I think this is what you're asking for when dealing with pointers and forward declaration.
I think "forward reference" with respect to pointers means something like this:
struct MyStruct *ptr; // this is a forward reference.
struct MyStruct
{
struct MyStruct *next; // another forward reference - this is much more useful
// some data members
};
The pointer is declared before the structure it points to is defined.
The compiler can get away with this because the pointer stores an address, and you don't need to know what is at that address to reserve the memory for the pointer.
Forward reference is when you declare a type but do not define it.
It allows you to use the type by pointer (or reference for C++) but you cannot declare a variable.
This is a way to say to the compiler that something exists
Say that you have a Plop structure defined in Plop.h:
struct Plop
{
int n;
float f;
};
Now you want to add some utility functions that works with that struct. You create another file PlopUtils.h (let's say you can't change Plop.h):
struct Plop; // Instead of including Plop.h, just use a forward declaration to speed up compile time
void doSomething(Plop* plop);
void doNothing(Plop* plop);
Now when you implement those function, you will need the structure definition, so you need to include the Plop.h file in your PlopUtils.cpp:
#include "PlopUtils.h"
#include "Plop.h" // now we need to include the header in order to work with the type
void doSomething(Plop* plop)
{
plop->n ...
}
void doNothing(Plop* plop);
{
plop->f ...
}
I think the C compiler originally had a pass in which it did symbol table building and semantic analysis together. So for example:
....
... foo(a,b) + 1 ... // assumes foo returns int
....
double foo(double x, double y){ ... } // violates earlier assumption
to prevent this, you say:
double foo(double x, double y); // this is the forward declaration
....
... foo(a,b) + 1 ... // correct assumptions made
....
double foo(double x, double y){ ... } // this is the real declaration
Pascal had the same concept.
Adding to previous answers. The typical situation in which forward reference is mandatory is when a struct foo contains a pointer to a struct bar, and bar contains a pointer to foo (a circular dependency between declarations). The only way to express this situation in C is to use a forward declaration, i.e.:
struct foo;
struct bar
{
struct foo *f;
};
struct foo
{
struct bar *b;
};
Forward references allow C compiler to do less passes and significantly reduces compilation time. It is probably was important some 20 years ago when computers was much slower and compliers less efficient.