C 宏 _Generic 给出了意外的编译器错误

标签 c c-preprocessor c11

使用 gcc.exe(Rev3,由 MSYS2 项目构建)8.2.0。

我试图构建一个宏来自动在两种类型之间进行类型转换,其中两个参数永远不应该是同一类型。我的问题是如果我不包含相同类型的情况,编译器会抛出错误。 我想要的:

#include <stdio.h>
#include <stdint.h>
// Macro to return string based on two different types
#define bob( to, from ) \
    _Generic( to , \
    int32_t: _Generic(from,  \
      int16_t: "s-l", \
      int8_t:  "c-l" ) , \
    int16_t: _Generic(from, \
      int32_t: "l-s", \
      int8_t:  "c-s") , \
    int8_t:_Generic(from, \
      int32_t: "l-c",  \
      int16_t: "s-c")  \
    )

    void main(void)
    {
        int32_t i1;
        int16_t s1;
        int8_t  c1;

        printf("%s\n", bob(i1,s1));
        printf("%s\n", bob(i1,c1));
        printf("%s\n", bob(s1,c1));
        printf("%s\n", bob(s1,i1));
        printf("%s\n", bob(c1,s1));
        printf("%s\n", bob(c1,s1));

    }

$ gcc gbug.c -o gbug.exe
gbug.c: In function 'main':
gbug.c:23:27: error: '_Generic' selector of type 'short int' is not compatible with any association
     printf("%s\n", bob(i1,s1));
                           ^~
gbug.c:9:19: note: in definition of macro 'bob'
 int16_t: _Generic(from, \
                   ^~~~
gbug.c:24:27: error: '_Generic' selector of type 'signed char' is not compatible with any association
     printf("%s\n", bob(i1,c1));
                           ^~
gbug.c:12:17: note: in definition of macro 'bob'
 int8_t:_Generic(from, \
                 ^~~~
gbug.c:25:27: error: '_Generic' selector of type 'signed char' is not compatible with any association
     printf("%s\n", bob(s1,c1));
                           ^~
gbug.c:12:17: note: in definition of macro 'bob'
 int8_t:_Generic(from, \
                 ^~~~
gbug.c:26:27: error: '_Generic' selector of type 'int' is not compatible with any association
     printf("%s\n", bob(s1,i1));
                           ^~
gbug.c:6:19: note: in definition of macro 'bob'
 int32_t: _Generic(from,  \
                   ^~~~
gbug.c:27:27: error: '_Generic' selector of type 'short int' is not compatible with any association
     printf("%s\n", bob(c1,s1));
                           ^~
gbug.c:9:19: note: in definition of macro 'bob'
 int16_t: _Generic(from, \
                   ^~~~
gbug.c:28:27: error: '_Generic' selector of type 'short int' is not compatible with any association
     printf("%s\n", bob(c1,s1));
                           ^~
gbug.c:9:19: note: in definition of macro 'bob'
 int16_t: _Generic(from, \

这个例子是我发现的最简单的例子。

如果我像这样添加“相同类型”转换行:

#define bob( to, from ) \
_Generic( to , \
int32_t: _Generic(from,  \
  int16_t: "s-l", \
  int32_t: "bug", \
  int8_t: "c-l" ) , \
int16_t: _Generic(from, \
  int32_t: "l-s", \
  int16_t: "bug", \
  int8_t: "c-s") , \
int8_t:_Generic(from, \
  int32_t: "l-c",  \
  int8_t: "bug", \
  int16_t: "s-c")  \
)

它以预期的结果构建和运行:

$ ./gbug.exe
s-l
c-l
c-s
l-s
s-c
s-c

验证我没有使用宏来扩展任何相同类型的条件。 我知道 _Generic 不是字符串替换宏,但我也认为如果您可以在没有默认情况下使用它,如果您使用未知类型(或不受支持的类型组合,这是我想要的行为),它会正确地抛出编译错误) 就像预处理器混淆了两个宏参数。

编辑:所以我有了更好的理解,(请参阅下面的回答)但如果两个参数类型相同,我仍然希望让宏抛出编译错误。到目前为止,我有一个强制链接错误的技巧,它仍然比运行时错误好。

最佳答案

问题是泛型选择的每个分支都必须有效,即使它们未被评估也是如此。

例如,您的第一个宏:

bob(i1, s1)

扩展为(为清楚起见添加的类型):

_Generic( ((int32_t) i1),
  int32_t: _Generic( ((int16_t) s1),
    int16_t: "s-l",
    int8_t:  "c-l" ),
  int16_t: _Generic( ((int16_t) s1),  // The error is here
    int32_t: "l-s",
    int8_t:  "c-s"),
  int8_t:_Generic( ((int16_t) s1),
    int32_t: "l-c",
    int16_t: "s-c")
)

显然 uint32_t 分支是有效的:它只是选择了 "s-l"。但是 int16_t 分支无效,因为 from(int16_t 本身)没有相应的分支。

在这种特殊情况下,添加一个不执行任何操作的自转换运算符不会有什么坏处。

关于C 宏 _Generic 给出了意外的编译器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55247506/

相关文章:

找不到输入文件 'libc.lib'

c - 指向数据类型的单个对象/实例的指针的命名

c - 在C中使用安全打印功能

c - 使用 __thread 时 gdb 优化了值

c - sysinfo 系统调用未返回正确的 freeram 值

c 函数在调用时不打印并跳转到下一个函数

c - 在使用#ifndef 的#undef 之后#define 没有按预期工作

c++ - 为什么我的宏参数之一被替换为 ')' 而不是标识符?

c - 在预处理输出中保留包含语句

c - 未命名的位字段是否具有明确定义的语义?