C宏_Generic产生意外的编译器错误

bd2*_*357 7 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));

    }
Run Code Online (Sandbox Code Playgroud)

$ 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, \
Run Code Online (Sandbox Code Playgroud)

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

如果我添加“相同类型”的转换行,如下所示:

#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")  \
)
Run Code Online (Sandbox Code Playgroud)

它生成并以预期的结果运行:

$ ./gbug.exe
s-l
c-l
c-s
l-s
s-c
s-c
Run Code Online (Sandbox Code Playgroud)

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

编辑:因此,我有一个更好的理解,(请参阅下面的答案),但是如果两个参数是同一类型,则仍希望获取该宏以引发编译错误。到目前为止,我有一个技巧来强制执行链接错误,该错误仍然比运行时错误好。

Art*_*yer 6

问题在于,即使不对其进行评估,泛型选择的每个分支也必须有效。

例如,您的第一个宏:

bob(i1, s1)
Run Code Online (Sandbox Code Playgroud)

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

_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")
)
Run Code Online (Sandbox Code Playgroud)

显然,uint32_t分支是有效的:它仅选择"s-l"。但int16_t分支是不是有效的,因为from(安int16_t本身)不具有相应的分支。

在这种特定情况下,添加不执行任何操作的自转换运算符不会有任何问题。

  • 这是重要的原因之一,泛型选择是语言语法的一部分,而不是宏扩展的一种形式。所有涉及的表达式都必须符合语言要求,其中包括,泛型选择的自变量表达式可以按类型与泛型关联之一匹配。这是一个*约束*,不少。这样的表情不被“评估”并不重要。 (2认同)