【问题标题】:Fix gcc warnings with _Generic macro and compound literals使用 _Generic 宏和复合文字修复 gcc 警告
【发布时间】:2020-07-20 19:26:54
【问题描述】:

我有一个结构,其中有一个联合和一个同类枚举。我制作了一个宏,它输出结构的复合文字,根据传递给宏的类型设置联合的种类和数据使用_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"));
}

它确实使用 gcc 编译,然后正确运行它输出:

mystruct (num): 2
mystruct (str): 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}, \
      |                                     ^

我尝试过像这样在复合文字中进行强制转换:

int: (struct mystruct){K_NUM, .num=(int)X}, \
char *: (struct mystruct){K_STR, .str=(char *)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"));
      |                 ^~~~~~~~

【问题讨论】:

  • (int)X --> (int)(intptr_t)(X) 安静 [-Wpointer-to-int-cast]

标签: c generics gcc gcc-warning compound-literals


【解决方案1】:

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

_Generic(2, int: (struct mystruct){K_NUM, .num=2}, char *: (struct mystruct){K_STR, .str=2}

即使char* 的情况没有被执行,它仍然会被编译并且将整数分配给字符串.str=2 是无效的C。

考虑采用完全不同的方法。例如,将宏参数保留在 _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");
}

【讨论】:

  • .str=2 是有效的 C - 有点。
  • @chux-ReinstateMonica No. stackoverflow.com/questions/52186834/…
  • 有趣的“编译器不允许不显示消息就让代码通过。” --> 所以代码可以通过并带有一条消息进行编译。我曾预料到违反约束会阻止编译。
  • @chux-ReinstateMonica “编译”在标准 C 中并不是真正的概念,编译器错误也不是。该标准只是谈到“实施”以及它必须如何显示“诊断信息”。如果“实现”显示一条消息,然后选择生成具有随机行为的二进制文件,它仍然符合标准。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多