使用_通用宏和复合文本修复gcc警告

使用_通用宏和复合文本修复gcc警告,c,generics,gcc,gcc-warning,compound-literals,C,Generics,Gcc,Gcc Warning,Compound Literals,我有一个结构,其中有一个并集和一个类似的枚举。我制作了一个宏,它输出结构的复合文本,根据传递给宏use\u Generic的类型设置联合的种类和数据 示例代码: #include <stdio.h> struct mystruct { enum { K_NUM, K_STR } kind; union { int num; char * str; }; }; #define MYSTRUCT(X) _Generic((X), \ int: (struct

我有一个结构,其中有一个并集和一个类似的枚举。我制作了一个宏,它输出结构的复合文本,根据传递给宏use\u Generic的类型设置联合的种类和数据

示例代码:

#include <stdio.h>

struct mystruct {
    enum { K_NUM, K_STR } kind;
    union { int num; char * str; };
};

#define MYSTRUCT(X) _Generic((X), \
    int: (struct mystruct){K_NUM, .num=X}, \
    char *: (struct mystruct){K_STR, .str=X} \
)

void print_mystruct(struct mystruct s) {
    switch (s.kind) {
    case K_NUM: printf("mystruct (num): %d\n", s.num); break;
    case K_STR: printf("mystruct (str): %s\n", s.str); break;
    }
}

int main() {
    print_mystruct(MYSTRUCT(2));
    print_mystruct(MYSTRUCT("test"));
}
但我得到了所有这些警告:

c.c: In function 'main':
c.c:21:26: warning: initialization of 'char *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   21 |  print_mystruct(MYSTRUCT(2));
      |                          ^
c.c:10:40: note: in definition of macro 'MYSTRUCT'
   10 |  char *: (struct mystruct){K_STR, .str=X} \
      |                                        ^
c.c:21:26: note: (near initialization for '(anonymous).<anonymous>.str')
   21 |  print_mystruct(MYSTRUCT(2));
      |                          ^
c.c:10:40: note: in definition of macro 'MYSTRUCT'
   10 |  char *: (struct mystruct){K_STR, .str=X} \
      |                                        ^
c.c:22:26: warning: initialization of 'int' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
   22 |  print_mystruct(MYSTRUCT("test"));
      |                          ^~~~~~
c.c:9:37: note: in definition of macro 'MYSTRUCT'
    9 |  int: (struct mystruct){K_NUM, .num=X}, \
      |                                     ^
c.c:22:26: note: (near initialization for '(anonymous).<anonymous>.num')
   22 |  print_mystruct(MYSTRUCT("test"));
      |                          ^~~~~~
c.c:9:37: note: in definition of macro 'MYSTRUCT'
    9 |  int: (struct mystruct){K_NUM, .num=X}, \
      |                                     ^
c.c: In function 'main':
c.c:9:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
    9 |  int: (struct mystruct){K_NUM, .num=(int)X}, \
      |                                     ^
c.c:22:17: note: in expansion of macro 'MYSTRUCT'
   22 |  print_mystruct(MYSTRUCT("test"));
      |                 ^~~~~~~~
但我得到了不同的警告:

c.c: In function 'main':
c.c:21:26: warning: initialization of 'char *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   21 |  print_mystruct(MYSTRUCT(2));
      |                          ^
c.c:10:40: note: in definition of macro 'MYSTRUCT'
   10 |  char *: (struct mystruct){K_STR, .str=X} \
      |                                        ^
c.c:21:26: note: (near initialization for '(anonymous).<anonymous>.str')
   21 |  print_mystruct(MYSTRUCT(2));
      |                          ^
c.c:10:40: note: in definition of macro 'MYSTRUCT'
   10 |  char *: (struct mystruct){K_STR, .str=X} \
      |                                        ^
c.c:22:26: warning: initialization of 'int' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
   22 |  print_mystruct(MYSTRUCT("test"));
      |                          ^~~~~~
c.c:9:37: note: in definition of macro 'MYSTRUCT'
    9 |  int: (struct mystruct){K_NUM, .num=X}, \
      |                                     ^
c.c:22:26: note: (near initialization for '(anonymous).<anonymous>.num')
   22 |  print_mystruct(MYSTRUCT("test"));
      |                          ^~~~~~
c.c:9:37: note: in definition of macro 'MYSTRUCT'
    9 |  int: (struct mystruct){K_NUM, .num=X}, \
      |                                     ^
c.c: In function 'main':
c.c:9:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
    9 |  int: (struct mystruct){K_NUM, .num=(int)X}, \
      |                                     ^
c.c:22:17: note: in expansion of macro 'MYSTRUCT'
   22 |  print_mystruct(MYSTRUCT("test"));
      |                 ^~~~~~~~

这是因为每次调用宏时,宏参数
X
都是 发现的是扩展的。所以当你通过
2
时,你会得到

_Generic(2, int: (struct mystruct){K_NUM, .num=2}, char *: (struct mystruct){K_STR, .str=2}
即使没有执行
char*
大小写,它仍然被编译,并且为字符串
.str=2
分配一个整数是无效的

考虑采取完全不同的方法。例如,将宏参数保留在_Generic列表之外。由于类型在编译时已知,您甚至需要枚举吗

#include <stdio.h>

void print_int (int x) { printf("%d\n", x); }
void print_str (const char* x) { puts(x); }

#define print(x) _Generic((x), \
  int:    print_int,           \
  char*:  print_str ) (x)

int main(void) 
{
  print(2);
  print("test");
}
#包括
void print_int(int x){printf(“%d\n”,x);}
void print_str(const char*x){puts(x);}
#定义打印(x)\通用((x)\
int:print_int\
字符*:打印字符(x)
内部主(空)
{
印刷品(2);
打印(“测试”);
}

.str=2
是有效的C-类。@chux-No.interest“编译器不允许在不显示消息的情况下让代码通过。”-->因此代码可以通过消息并编译。我原以为违反约束会阻止编译。@chux“编译”在标准C中不是一个真正的概念,编译器错误也不是。该标准只提到了“实现”以及它必须如何显示“诊断消息”。如果“实现”显示一条消息,然后选择生成一个具有随机行为的二进制文件,尽管如此,它仍然符合标准。
(int)X
-->
(int)(intptr_t)(X)
到静默[-Wpointer到int cast]