我写了一些编写结构{a,b,c,d,e}的宏。 但是这个宏能够接收5个或更少的参数。如果它接收少于5个参数,则它应该在结构中放置0。
我试图制作一个重复" 0," N次,但由于这个N是参数的数量,它不是"硬编码的"值,所以我不能将它与重复0的宏连接起来。
我想知道是否有任何方法可以在宏上拥有默认值。
#define REPEAT1(s) s
#define REPEAT2(s) s, s
#define REPEAT3(s) s, REPEAT2(s)
...
#define REPEATN(n, s) REPEAT ## n (s)
...
{__VA_ARGS__, REPEATN((5 - VA_ARGS_NUM(__VA_ARGS__)), 0)}
// can't work because ## will not create a valid token with REPEAT and (5 - ....)
答案 0 :(得分:3)
默认情况下,C将所有其他未初始化的设置为0。
例如:
typedef struct {
int a,b,c,d,e,f;
} myStruct;
myStruct str = {1, 2, 3};
现在您的值为str.a = 1, str.b = 2 and str.c = 3
,而其他所有值都设为0
。
但是,如果你这样做:
myStruct str;
然后你不要为0
设置任何东西,特别是如果这是在堆栈上声明的局部变量。
如果变量是全局变量,那么如果链接器在启动时将全局变量设置为0
,则可以将其设置为0
。
答案 1 :(得分:1)
如果接收的参数少于5个,则应在结构中加0。
这可以通过使用复合文字来解决。首先,我们可以使用复合文字创建一个宏来确定VA_ARGS的数量,因为没有标准的宏:
#define ARGS_N(...) (sizeof((int[]){ __VA_ARGS__ }) / sizeof(int))
这可用于确定项目数。在这种情况下,如果恰好有5个,则应使用这些值初始化结构,否则应将其初始化为0.
然后我们可以使用上面的宏来创建条件初始化列表。鉴于一些结构:
typedef struct
{
int a;
int b;
int c;
int d;
int e;
} test_t;
我们可以通过自定义方法初始化该结构的实例:
test_t t1 = TEST_INIT(1,2,3);
将实现为:
#define TEST_INIT(...) (ARGS_N(__VA_ARGS__)==5) ? (test_t){__VA_ARGS__} : (test_t){0}
不幸的是,一些编译器(gcc)会抱怨缺少初始值设定项,因为条件的两个路径都被扩展,即使只评估了一个。在这种情况下,我们可以安全地告诉gcc闭嘴:
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
完整计划:
#include <stdio.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
typedef struct
{
int a;
int b;
int c;
int d;
int e;
} test_t;
#define ARGS_N(...) (sizeof((int[]){ __VA_ARGS__ }) / sizeof(int))
#define TEST_INIT(...) (ARGS_N(__VA_ARGS__)==5) ? (test_t){__VA_ARGS__} : (test_t){0}
int main (void)
{
test_t t1 = TEST_INIT(1,2,3);
test_t t2 = TEST_INIT(1,2,3,4,5);
printf("%d %d %d %d %d\n", t1.a, t1.b, t1.c, t1.d, t1.e);
printf("%d %d %d %d %d\n", t2.a, t2.b, t2.c, t2.d, t2.e);
}
#pragma GCC diagnostic pop
输出:
0 0 0 0 0
1 2 3 4 5