Примечание: Я только отвечаю на вопрос, как написать определение struct
. Я не вижу способа заставить препроцессор автоматически генерировать код сериализации и десериализации по нескольким причинам. Во-первых, невозможно извлечь токен - имя члена - из аргумента макроса, даже если вы знаете, какой токен извлечь. Во-вторых, вы можете использовать функцию C11 _Generic
для создания вызовов предопределенных функций сериализации / десериализации с указанием типа c. Но для вызова _Generic
требуется полный список возможностей, поэтому наращивание возможностей будет невозможно. Я думаю, вы обнаружите, что существующие системы, которые автоматически генерируют код сериализации / десериализации, зависят от внешних генераторов кода. Это гораздо более гибкая (и, вероятно, более простая) стратегия.
Итак, вернемся к автогенерации объявлений структуры. Как уже упоминалось, это действительно возможно, только если вы генерируете макросы N , по одному на каждое количество аргументов. Также вам нужен способ вычисления N , для которого может потребоваться больше автоматически генерируемых макросов. В общем, гораздо проще использовать фреймворк, такой как P99 .
Дженса Гастта. Вот очень упрощенная иллюстрация того, как это сделать, с небольшим ограничением полей, поскольку шаблоны очевидно.
Мы начнем с макроса, который будет вычислять количество аргументов в вызове variadi c. Обратите внимание, что это будет правильно возвращать 0, если нет аргументов variadi c. Надежное решение, такое как P99, справится с этим правильно. Но в этом случае это не имеет значения, потому что struct
без членов не разрешено C, поэтому мы знаем, что должен быть хотя бы один аргумент. (Это не было бы правдой в 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)
Теперь нам нужно восемь макросов, которые создают члены. Все, что им нужно сделать, это вставить точку с запятой между аргументами, так что это не очень сложно:
#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;
Наконец, нам нужно собрать все это вместе. Для этого нам понадобится макрос, который может объединить имя макроса:
#define PASTE3(a, b, c) PASTE3_(a, b, c)
#define PASTE3(a, b, c) a ## b ## c
Наконец, макрос, который создает структуру
#define MY_STRUCT(name, ...) \
typedef struct name name; \
struct name { \
PASTE3(S, NARGS(__VA_ARGS__), _)(__VA_ARGS__) \
};
И теперь мы можем попробуйте все это:
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);
Вот что gcc -E
производит, учитывая все вышеперечисленное: (Примечание: я не могу комментировать, работает ли это на различных версиях MSV C. Но это все стандартно 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; };