I want to have a macro
#define MY_STRUCT( /* ... /*) /* ... */
That I want to call this way
MY_STRUCT(point, double x, int y);
Which expands to this
typedef struct {
double x;
int y;
} point;
void init_point(point *p) {
p->x = load_double_from_somewhere();
p->y = load_int_from_somewhere();
}
The macro should be able to handle any number of parameters I give it. I'm trying to generate data bindings for model objects automatically through macros for I've been writing mapping functions by hand and it's tiresome and repetitive (xml to C struct).
I know it's possible but I can't figure out how.
Note: I'm only addressing the question of how to write the struct definition. I don't see a way to get the preprocessor to automatically generate serialisation and deserialisation code, for a couple of reasons. First, it's not possible to extract a token --the member name-- from a macro argument, even if you could know which token to extract. Second, you could use C11's _Generic feature to create calls to pre-defined type-specific serialisation/deserialisation functions. But the _Generic call needs a complete list of possibilites, so it's not going to be possible to incrementally build up the possibilities. I think you'll find that existing systems which autogenerate serialisation/deserialisation code depend on external code generators. That's a much more flexible (and probably easier) strategy.
So, back to autogenerating struct declarations. As has been mentioned, this is really only possible if you generate N macros, one for every number of arguments. And you also need a way to compute N, which might require more automatically-generated macros. All in all, it's a lot easier to use a framework like Jens Gustedt's P99.
Here's a highly simplified illustration of how to do it, with a small limit of fields because the patterns are obvious.
We start with a macro which will compute the number of arguments in a variadic call. Note that this will note correctly return 0 if there are no variadic arguments. A robust solution, like P99, would handle that correctly. But in this case, it doesn't matter because a struct with no members is not allowed by C, so we know there must be at least one argument. (That wouldn't be true in C++.)
#define ARG9_(a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
#define NARGS(...) ARG9_(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
Now, we need eight macros which construct the members. All they have to do is insert semicolons between the arguments, so it's not very challenging:
#define S8_(first, ...) first; S7_(__VA_ARGS__)
#define S7_(first, ...) first; S6_(__VA_ARGS__)
#define S6_(first, ...) first; S5_(__VA_ARGS__)
#define S5_(first, ...) first; S4_(__VA_ARGS__)
#define S4_(first, ...) first; S3_(__VA_ARGS__)
#define S3_(first, ...) first; S2_(__VA_ARGS__)
#define S2_(first, ...) first; S1_(__VA_ARGS__)
#define S1_(first) first;
Finally, we need to put all that together. To do so, we're going to need a macro which can concatenate up a macro name:
#define PASTE3(a, b, c) PASTE3_(a, b, c)
#define PASTE3_(a, b, c) a ## b ## c
Finally, the macro which creates the struct
#define MY_STRUCT(name, ...) \
typedef struct name name; \
struct name { \
PASTE3(S, NARGS(__VA_ARGS__), _)(__VA_ARGS__) \
};
And now we can give it all a try:
MY_STRUCT(s1, int a);
MY_STRUCT(s2, int a, double b);
MY_STRUCT(s3, const char* s, int t[17], double sum);
MY_STRUCT(s4, char a, char b, char c, char d);
MY_STRUCT(s5, char a, char b, char c, char d, char e);
MY_STRUCT(s6, char a, char b, char c, char d, char e, char f);
MY_STRUCT(s7, char a, char b, char c, char d, char e, char f, char g);
MY_STRUCT(s8, char a, char b, char c, char d, char e, char f, char g, short h);
Here's what gcc -E produces, given all of the above: (Note: I can't comment on whether this works on various versions of MSVC. But it's all standard C99.)
# 1 "nargs.h"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "nargs.h"
# 22 "nargs.h"
typedef struct s1 s1; struct s1 { int a; };
typedef struct s2 s2; struct s2 { int a; double b; };
typedef struct s3 s3; struct s3 { const char* s; int t[17]; double sum; };
typedef struct s4 s4; struct s4 { char a; char b; char c; char d; };
typedef struct s5 s5; struct s5 { char a; char b; char c; char d; char e; };
typedef struct s6 s6; struct s6 { char a; char b; char c; char d; char e; char f; };
typedef struct s7 s7; struct s7 { char a; char b; char c; char d; char e; char f; char g; };
typedef struct s8 s8; struct s8 { char a; char b; char c; char d; char e; char f; char g; short h; };
I do not know what you need it for, but ...
#define x(a,b,c) struct a {b;c;}
x(mystr, int m, double n);
and the result is:
struct mystr {int m;double n;};
or
#define x(a,b,c) typedef struct {b;c;} a
x(mystr, int m, double n);
and the result
typedef struct {int m;double n;} mystr;
I'm not sure if it's possible to extract x from double x (unless you know all possible types your variables can have).
Also, iterating over comma-separated lists using preprocessor requires writing boilerplate macros (O(n) of them, I think). Boost.Preprocessor might help with that, but you can completely avoid boilerplate if you use a different syntax:
MY_STRUCT(point, (double,x)(double,y))
Implementation:
#define MY_STRUCT(name, seq) \
typedef struct { \
MY_STRUCT_impl_end(MY_STRUCT_impl_decl_loop_a seq) \
} name; \
void init_point(name *p) { \
MY_STRUCT_impl_end(MY_STRUCT_impl_load_loop_a seq) \
}
#define MY_STRUCT_impl_end(...) MY_STRUCT_impl_end_(__VA_ARGS__)
#define MY_STRUCT_impl_end_(...) __VA_ARGS__##_end
#define MY_STRUCT_impl_decl_loop(type, name) type name;
#define MY_STRUCT_impl_decl_loop_a(...) MY_STRUCT_impl_decl_loop(__VA_ARGS__) MY_STRUCT_impl_decl_loop_b
#define MY_STRUCT_impl_decl_loop_b(...) MY_STRUCT_impl_decl_loop(__VA_ARGS__) MY_STRUCT_impl_decl_loop_a
#define MY_STRUCT_impl_decl_loop_a_end
#define MY_STRUCT_impl_decl_loop_b_end
#define MY_STRUCT_impl_load_loop(type, name) p->name = load_##name##_from_somewhere();
#define MY_STRUCT_impl_load_loop_a(...) MY_STRUCT_impl_load_loop(__VA_ARGS__) MY_STRUCT_impl_load_loop_b
#define MY_STRUCT_impl_load_loop_b(...) MY_STRUCT_impl_load_loop(__VA_ARGS__) MY_STRUCT_impl_load_loop_a
#define MY_STRUCT_impl_load_loop_a_end
#define MY_STRUCT_impl_load_loop_b_end
If you want to autogenerate source code, the preprocessor is the worst tool you can get.
And you absolutely cannot create any macro to generate a struct with any number of fields; the C preprocessor does not support loops or recursion.
But if a maximum of 8 fields/arguments are enough, though NON-STANDARD, this will do in gcc and clang:
#define MY_STRUCT(name, ...) struct name { C2SC(__VA_ARGS__,,,,,,,,,) }
#define C2SC(a, b, c, d, e, f, g, h, ...) a; b; c; d; e; f; g; h;
MY_STRUCT(foo, int bar, int baz, void *quux, void *xuq, char sq[12]);
This deliberately creates a struct name { ... }, not a typedef struct { ... } name as in the OP: It's already obtuse enough even without a MY_STRUCT macro which actually generates a typedef.
I have a struct defined as:
typedef struct coro_context {
int id;
jmp_buf env;
list_head list;
jmp_buf waiter;
long timeout;
void *private;
char stack[0];
} coro_context;
which I need to initialize with three values
id = 0
private = function pointer
append to end of struct a suitable char array of length size
My current attempt looks like (the "unsigned long" bit is to get the right alignment):
#define CORO_CONTEXT(name,size) \
unsigned long __##name##_ctx[(sizeof(coro_context)+size)/sizeof(unsigned long)]={0};\
coro_context *name##_ctx = (coro_context *)__##name##_ctx
This works, but has two problems (ok, problems are one and a half ;) ):
it is UGLY (half problem).
I see no way to statically initialize private = name.
Note: I insist on "static initialization" because I want to use this in plain "C" (c11 is ok, if required) because I need to use these initialization outside function context.
I'd use a union overlaying the struct coro_context instance with a char buffer:
#include <setjmp.h>
typedef struct coro_context {
int id;
jmp_buf env;
list_head list;
jmp_buf waiter;
long timeout;
void *private;
char stack[]; /*should be [] in C11, [0] is not valid C */
} coro_context;
/*shouldn't start globals with underscore*/
/*shouldn't violate aliasing rules*/
/*C11 compound literals obviate the need for an extra global identifier*/
#define CORO_CONTEXT(name,size) \
coro_context *name##_ctx = &(union { coro_context ctx; char buf[sizeof(coro_context)+size]; }){ .ctx={ .private=&name } }.ctx;
int my_name;
CORO_CONTEXT(my_name,32)
and then take the address of .ctx. That should also get rid off the aliasing issues your solution has.
You'll need to initialize with an address of a global, because the value of a global is not usable in static initializations.
If you want something C99 compatible, you will need the extra identifier, but it shouldn't start with two underscores:
#include <setjmp.h>
typedef struct coro_context {
int id;
jmp_buf env;
list_head list;
jmp_buf waiter;
long timeout;
void *private;
char stack[1]; /*c99 doesn't have flexible array members*/
} coro_context;
#define CORO_CONTEXT(name,size) \
union { coro_context ctx; char buf[sizeof(coro_context)+size]; } name##_ctx__ = { { 0, {0},{0},{0}, 0, &name } }; \
coro_context *name##_ctx = &name##_ctx__.ctx;
int my_name;
CORO_CONTEXT(my_name,32)
First note that the size of the long buffer, may not match what you expect,as it is rounded to floor. for example if core_context size is 10 bytes, and one requested additional size of 3 bytes, and assuming long size is 8 bytes. you get (10+3)/8 = 1, so you allocate 1 long for handling 13 bytes (instead of allocating 2 longs).
so instead of
unsigned long __##name##_ctx[(sizeof(coro_context)+size)/sizeof(unsigned long)]={0};
I think it shall be
unsigned long __##name##_ctx[(sizeof(coro_context)+size+sizeof(unsigned long))/sizeof(unsigned long)]={0};
now regarding the static initialization, I wouldn't use long buffer, but create a new struct with the same first n variables, and with the requested sized buffer at end. this struct can be initialized statically, and the requested pointer will point to it. so the code would look like this:
#define CORO_CONTEXT(name,size,my_private_method) \
typedef struct coro_context##_name {\
int id;\
jmp_buf env;\
list_head list;\
jmp_buf waiter;\
long timeout;\
void *private;\
char stack[0];\
char additional_buffer[size];\
} coro_context##name;\
coro_context##name __name##_ctx = {0,0,0,0,0,my_private_method};\
coro_context *name##_ctx = (coro_context *)&__name##_ctx
for sake of simplicity, you can examine also this code using simplified struct, and using the coro_context struct as "base" of the wrapper struct (i.e. single variable instead of declaring all coro_context variables):
typedef struct coro_context {
int id;
void *private;
} coro_context;
#define DECLARE_CORO_CONTEXT(size,private_method)\
typedef struct wrapper_for_core_context\
{\
coro_context base;\
char buffer[size];\
}wrapper;\
wrapper my_wrapper = { {0, private_method}, 0 };\
coro_context *cc = (coro_context *)&my_wrapper;
//now the using code
DECLARE_CORO_CONTEXT( 20, test_at_avro_bytes_field_all_data_values );
I have a struct that might have 2 or 4 members depending on a preprocessor definition.
struct foo {
int m1;
int m2;
#ifdef MORE_MEMBERS
int m3;
int m4;
#endif
}
I have functions that take foo.m3 and foo.m4 as arguments. Because of that, I get a compilation error when MORE_MEMBERS isn't defined.
I'm trying to avoid adding #ifdef at every function call. Is there some way to make m3 and m4 be aliases/dummies when MORE_MEMBERS isn't defined? I'd like to still keep the struct size equal to sizeof(int) * 2.
I agree with Iharob, it's horrible code. It's not too clear what you're after, but it sounds like you could use a union:
struct foo
{
int a;
int b;
};
union bar
{
struct foo m1m2;
struct foo m3m4;
};
void f(union bar *x)
{
printf("%d", x->m1m2.a);
printf("%d", x->m3m4.b);
}
Im having an issue in my program where I define a structure type but not a structure variable in a header as such.
typedef struct
{
int a;
int b;
int c;
Token d;
} Foo;
I then want to use this struct foo later on in a .c file that does infix to postfix
#include "header"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
int infix2postfix(char *infix, Arr arr)
{
struct Foo foo;
char szToken[MAX_TOKEN];
Stack stack = newStack();
infix = getToken(infix, szToken, MAX_TOKEN); //provides next token to be scanned by function.
... //push pop using switch case didn't post code for simplicity.
case...
push(stack, *foo.a);
...
case...
pop(stack);
...
goOut(arr, *foo.d); //goOut(function that populates and "arr" Array from printing.
}
So when I compile here I get
error: storage size of ‘foo’ isn’t known struct Foo foo;
I have tried struct Foo *foo = malloc(sizeof foo); to allocate memory but it messes up my push(stack, *foo.a); and goOut(arr, *foo.d); How do I go about fixing this? Do I have to allocate memory in the infix2postfix function first then declare a structure variable?
You defined a type Foo which is a tagless struct type. You could have a separate struct Foo { int anonymous; char name[MAX_NAME]; }; which is wholly unrelated to the type Foo. (It would be very confusing for humans, but the compiler would have no problem.)
In your function, you should write:
int infix2postfix(char *infix, Arr arr)
{
Foo foo;
you have already defined Foo as a typedef struct, so you do not use struct Foo again to declare foo, just use
Foo foo; to declare not struct Foo foo;
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;
};