Define a struct based on the definition of an existing struct - c

If I have an arbitrary struct, is there any way that I can use a macro to add a field to that struct?
for example:
struct foo{
int a,
int b
};
MAGIC(foo, newtype, newname);
Which would evaluate to:
struct foo{
int a;
int b;
};
struct magic_foo{
int a;
int b;
newtype newname;
};
I know this is a stretch, but I'm thinking there might be some built in macro that retrieves the definition of a struct from it's name?

Not directly, since the preprocessor is completely unaware of the C syntax (it operates only as a token replacer; introspection for previously declared types is impossible).
Maybe this is a way to go:
#define STRUCT { \
int a; \
int b; \
EXTRA_MEMBER_DECL \
}
#define EXTRA_MEMBER_DECL /* empty */
struct foo STRUCT;
#define EXTRA_MEMBER_DECL newtype newname;
struct bar STRUCT;
Plan B could be using a nested struct:
struct bar {
struct foo;
newtype newmember;
};

Related

manage similar structs, one with arrays, the other with pointers

I have some structs containing arrays
struct mystruct_withArrays {
int foo;
int bar[MaxN];
int baz[MaxM];
}
and their equivalent with pointers
struct mystruct_withPointers {
int foo;
int *bar;
int *baz;
}
and I want to avoid the double definition. This is I want to make something as a template
#define myStruct(M,N)
...
such that myStruct(MaxM,MaxN) produces the array struct and myStruct(,) produces the struct with pointers.
Moreover, of course I want to do the same technique for multiple structs and to have automatic mapping from arrays to pointers. A final use case could be as follow
#include "mystructs.h"
//globals, for huge space usage
struct myStructA(1000,10000) hugeA;
struct myStructB(1024*1024) * hugeB;
void main(){
struct myStructA(,) smallA;
struct myStructB() smallB;
mapStruct(hugeA,smallA) //this is a macro
mapStruct(hugeB,smallB) //this is a macro
doSomething(smallA);
doSomethingMore(smallA,smallB);
doSomethingDetailed(smallB.qux);
}
where mapStruct(hugeA, smallA) is the obvious mapping smallA.bar = hugeA.bar, etc. The expanded code would be:
struct myStructA(1000,10000) hugeA;
struct myStructB(1024*1024) hugeB;
struct mystructA_withArrays {
int foo;
int bar[1000];
int baz[10000];
} hugeA;
struct mystructB_withArrays * {
int qux[1048576];
int quux[1048576];
} hugeB;
void main(){
struct mystructA_withPointers {
int foo;
int * bar;
int * baz;
} smallA;
struct mystructB_withArrays {
int * qux;
int * quxx;
} smallB;
smallA.bar=hugeA.bar;
smallA.baz=hugeA.baz;
smallB.qux=hugeB.qux;
smallB.quxx=hugeB.quxx;
doSomething(smallA);
doSomethingMore(smallA,smallB);
doSomethingDetailed(smallB.qux);
}
As you can see, the general idea is that some variables are allocated outside of the stack, but still without using malloc, just declaring them as globals. Even in some use case they are external globals from a linked shared object.
EDIT:
about memory performance, it is not easy to ascertain if malloc structs are better or worse than global struct. It depends also on the flag -mcmodel of the compiler
The sensible KISS solution seems to be this:
struct mystruct {
int foo;
int *bar;
int *baz;
};
struct mystruct array =
{
.bar = (int[ 1000]){0},
.baz = (int[10000]){0},
};
struct mystruct pointers;
Now the interface of this struct is the same no matter how data was allocated and "array structs" are 100% compatible with "pointer structs". If declared at file scope, the allocation of the compound literals will end up in .bss, same deal as in your pseudo code.
A possible solution to create several similar structures might be the use of an X macro.
(Unlike the Wikipedia page, I pass the macro X as an argument instead of redefining the macro.)
I edited the code a bit to add the assignments of the arrays to the corresponding pointers. I used variadic macros to allow omitting the variable names in the argument list. This is to show the concept, there may be room for improvement.
Example file macro.c
#define LIST_OF_ARRAY_FIELDS_1(X, ...) \
X(int, bar, MaxN, __VA_ARGS__) \
X(int, baz, MaxM, __VA_ARGS__)
#define LIST_OF_ARRAY_FIELDS_2(X, ...) \
X(char, bla1, MaxK, __VA_ARGS__) \
X(char, bla2, MaxL, __VA_ARGS__)
#define CREATE_ARRAY_FIELD(type, name, size, ...) \
type name[size];
#define CREATE_POINTER_FIELD(type, name, size, ...) \
type *name;
struct mystruct_withArrays {
int foo;
LIST_OF_ARRAY_FIELDS_1(CREATE_ARRAY_FIELD)
}
struct mystruct_withPointers {
int foo;
LIST_OF_ARRAY_FIELDS_1(CREATE_POINTER_FIELD)
}
struct otherstruct_withArrays {
int foo;
LIST_OF_ARRAY_FIELDS_2(CREATE_ARRAY_FIELD)
}
struct otherstruct_withPointers {
int foo;
LIST_OF_ARRAY_FIELDS_2(CREATE_POINTER_FIELD)
}
mystruct_withArrays hugeA;
mystruct_withPointers smallA;
otherstruct_withArrays hugeB;
otherstruct_withPointers smallB;
#define ASSIGN_POINTERS(type, name, size, dest, src) \
dest.name = src.name;
LIST_OF_ARRAY_FIELDS_1(ASSIGN_POINTERS, smallA, hugeA)
LIST_OF_ARRAY_FIELDS_2(ASSIGN_POINTERS, smallB, hugeB)
Result:
$ gcc -E macro.c
# 1 "macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "macro.c"
# 15 "macro.c"
struct mystruct_withArrays {
int foo;
int bar[MaxN]; int baz[MaxM];
}
struct mystruct_withPointers {
int foo;
int *bar; int *baz;
}
struct otherstruct_withArrays {
int foo;
char bla1[MaxK]; char bla2[MaxL];
}
struct otherstruct_withPointers {
int foo;
char *bla1; char *bla2;
}
mystruct_withArrays hugeA;
mystruct_withPointers smallA;
otherstruct_withArrays hugeB;
otherstruct_withPointers smallB;
smallA.bar = hugeA.bar; smallA.baz = hugeA.baz;
smallB.bla1 = hugeB.bla1; smallB.bla2 = hugeB.bla2;

typedef syntax clarification

I have a bit of confusion between the below declarations - could you please help clear it up?
typedef struct {
int a;
int b;
} example;
And this
struct something {
int a;
int b;
} ob;
And I am not sure what the below would even mean?
typedef struct foo {
int a;
int b;
} bar;
typedef struct {
int a;
int b;
} example;
This one defines an unnamed structure type and introduces example as a type alias for that structure type. You can therefore refer to that structure type only as `example.
struct something {
int a;
int b;
} ob;
This one defines a structure type something and also declares an object ob of that type. You can refer to the structure type only as struct something.
typedef struct foo {
int a;
int b;
} bar;
This one defines a structure type named foo and introduces bar as a type alias for that structure type. You can refer to that structure type as struct foo or as bar.
With
typedef struct {
int a;
int b;
} example;
you define an unnamed structure, but define a type-alias example for the structure. That means you can only create instance of the structures using the example "type", like e.g.
example my_example_structure;
With
struct something {
int a;
int b;
} ob;
you define a structure named something, and an instance (a variable) of that structure named ob. You can use struct something to create new variables of the structure:
struct something my_second_ob;
The variable ob can be used like any other instance of the structure:
printf("b = %d\n", ob.b);
Lastly, with
typedef struct foo {
int a;
int b;
} bar;
you define a structure named foo, so you can use e.g. struct foo to define variables. You also define a type-alias bar which can also be used. Like for example
struct foo my_first_foo;
bar my_second_foo;
The general syntax for typedef is
typedef <actual type> <alias name>;
In the last case of your examples, the <actual type> is
struct foo {
int a;
int b;
}
and the <alias name is bar.

structs in different headers refer to each other

I want to have a struct that contains a pointer to another struct which in turn has a function pointer with the function argument being a pointer to the first type of struct but I'm struggling to resolve the references. The struct definitions are in different header files and must be available to other code in the full project.
In a simplified example, in main I have:
#include "a.h"
typedef struct {
int x;
int (*func)(a_t * a);
int y;
} z_t;
In a.h:
#ifndef A_H_
#define A_H_
#include "z.h"
typedef struct {
int b;
int c;
z_t * z;
} a_t;
#endif /* A_H_ */
and in z.h:
#ifndef Z_H_
#define Z_H_
#include "a.h"
typedef struct {
int x;
int (*func)(a_t * a);
int y;
} z_t;
#endif /* Z_H_ */
I end up with circular #includes and type a_t is unknown in z.h
Can anyone help?
In C, you can have a circular reference among two or more structures, or from a structure to itself. Note that the reference can be by pointer only: one structure X cannot embed an instance of another while simultaneously X embeds an instance of Y. However, X can have a pointer to Y, while Y can point to X, or embed a copy of X.
The mechanism which allows a circular reference in C is the incomplete struct type. In C you can use struct in a declaration, without defining the body of the struct, like this:
struct foo *bar; // foo has never been seen before.
The foo identifier is the "struct tag". A later re-declaration of the same struct tag in the same scope which does include a body will complete the type:
struct foo { int member; }; // foo is now complete
With this we can do:
struct list_node {
struct list_node *next, *previous; // self reference
};
struct foo {
struct bar *bar_ptr;
};
struct bar {
struct foo *foo_ptr; // mutual references
};
In your code, you haven't used a single struct tag; all your struct types are anonymous, and you are relying on typedef aliases. The above referential tricks cannot be played out using typedef names; the struct tags are essential.
Only a struct which has a tag can be declared two or more times: incomplete the first times, and then completely. The declaration of a struct with no tag is anonymous; such a declaration invents a new, unique struct type each time it appears.

typedef, structure and type compatibiliy

If I have these two structs:
struct
{
int x;
} A;
struct
{
int x;
} B;
then making A = B; results in a compilation error because the two anonymous structs are not compatible.
However if I do:
typedef struct
{
int x;
} S;
S A;
S B;
A = B; is a legal assignment because they are compatible.
But why? With typedef I understand that the compiler makes this when meet S A and S B:
struct { int x; } A;
struct { int x; } B;
so A and B should not be compatible...
Each anonymous struct declaration is a distinct type; this is why you get a type mismatch when trying to assign one to the other.
A typedef, however, declares an alias (i.e. a new name for something that already exists) for a type (it does not create a new type).
A typedef is also not a simple text replacement, like a preprocessor macro. Your statement
I understand that the compiler make this when meet S A and S B:
struct { int x; } A;
struct { int x; } B;
is where your understanding is wrong.
When you use the type alias S, as in
S A;
S B;
the types of both objects A and B are the same by definition and assigning one to the other is possible.
This is because C treats every untagged struct as a new kind of struct, regardless of the memory layout. However, typedef struct { } name; cannot be used if you want to use the struct in a linked list. You'll need to stick with defining a structure tag in this case, and typedef the tagged struct instead.
struct DistanceInMeter /* Anonymous 1 */
{
int x; /* distance */
};
struct VolumeInCC /* Anonymous 2 */
{
int x; /* volume */
};
struct DistanceInMeter A;
struct VolumeInCC B;
...
A = B; /* Something is wrong here */
Equating different type doesn't always make sense and thus is not allowed.
typedef struct DistanceInMeter /* Anonymous 1 */
{
int x; /* distance */
} Dist_t;
Dist_t C, D;
...
C = D; /* Alright, makes sense */

What's the syntactically proper way to declare a C struct?

I've seen C structs declared several different ways before. Why is that and what, if anything, does each do different?
For example:
struct foo {
short a;
int b;
float c;
};
typedef struct {
short d;
int e;
float f;
} bar;
typedef struct _baz {
short a;
int b;
float c;
} baz;
int main (int argc, char const *argv[])
{
struct foo a;
bar b;
baz c;
return 0;
}
Well, the obvious difference is demonstrated in your main:
struct foo a;
bar b;
baz c;
The first declaration is of an un-typedefed struct and needs the struct keyword to use. The second is of a typedefed anonymous struct, and so we use the typedef name. The third combines both the first and the second: your example uses baz (which is conveniently short) but could just as easily use struct _baz to the same effect.
Update: larsmans' answer mentions a more common case where you have to use at least struct x { } to make a linked list. The second case wouldn't be possible here (unless you abandon sanity and use a void * instead) because the struct is anonymous, and the typedef doesn't happen until the struct is defined, giving you no way to make a (type-safe) pointer to the struct type itself. The first version works fine for this use, but the third is generally preferred in my experience. Give him some rep for that.
A more subtle difference is in namespace placement. In C, struct tags are placed in a separate namespace from other names, but typedef names aren't. So the following is legal:
struct test {
// contents
};
struct test *test() {
// contents
}
But the following is not, because it would be ambiguous what the name test is:
typedef struct {
// contents
} test;
test *test() {
// contents
}
typedef makes the name shorter (always a plus), but it puts it in the same namespace as your variables and functions. Usually this isn't an issue, but it is a subtle difference beyond the simple shortening.
It's largely a matter of personal preference. I like to give new types a name starting with a capital letter and omit the struct, so I usually write typedef struct { ... } Foo. That means I cannot then write struct Foo.
The exception is when a struct contains a pointer to its own type, e.g.
typedef struct Node {
// ...
struct Node *next;
} Node;
In this case you need to also declare the struct Node type, since the typedef is not in scope within the struct definition. Note that both names may be the same (I'm not sure where the underscore convention originated, but I guess older C compilers couldn't handle typedef struct X X;).
All your uses are syntactically correct. I prefer the following usage
/* forward declare all structs and typedefs */
typedef struct foo foo;
.
.
/* declare the struct itself */
struct foo {
short a;
int b;
foo* next;
};
Observe that this easily allows to use the typedef already inside the declaration of the struct itself, and that even for struct that reference each other mutually.
The confusion comes about because some of the declarations are in fact declaring up to three C constructs. You need to keep in mind the difference between:
A typedef declaration,
A struct definition, and
A struct declaration.
They are all very different C constructs. They all do different things; but you can combine them into the one compound construct, if you want to.
Let's look at each declaration in turn.
struct foo {
short a;
int b;
float c;
};
Here we are using the most basic struct definition syntax. We are defining a C type and give it the name foo in the tag namespace. It can later be used to declare variables of that type using the following syntax:
struct foo myFoo; // Declare a struct variable of type foo.
This next declaration gives the type another name (alias) in the global namespace. Let's break it down into its components using the previous basic declaration.
typedef foo bar; // Declare bar as a variable type, the alias of foo.
bar myBar; // No need for the "struct" keyword
Now just replace "foo" with the the struct's definition and voila!
typedef struct {
short d;
int e;
float f;
} bar;
typedef struct _baz {
short a;
int b;
float c;
} baz;
The above syntax is equivalent to the following sequence of declarations.
struct _baz {
short a;
int b;
float c;
}
typedef _baz baz; // Declare baz as an alias for _baz.
baz myBaz; // Is the same as: struct _baz myBaz;

Resources