编程C:宏中的默认参数?

时间:2017-06-14 20:45:40

标签: c macros

我写了一些编写结构{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 - ....)

2 个答案:

答案 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