C11_泛型将真和假推断为整数

C11_泛型将真和假推断为整数,c,generics,c11,C,Generics,C11,在C11中,有一个\u Generic宏,它可以实现很酷的通用功能。但是,在正常情况下使用true和false会导致错误的推断: #include <stdio.h> #include <stdbool.h> #define TypeName(x) \ _Generic((x), \ bool: "bool", \ int: "int", \ default: "unknown") #if defined (__STDC_VERSION__

在C11中,有一个
\u Generic
宏,它可以实现很酷的通用功能。但是,在正常情况下使用
true
false
会导致错误的推断:

#include <stdio.h>
#include <stdbool.h>

#define TypeName(x) \
  _Generic((x), \
    bool: "bool", \
    int: "int", \
    default: "unknown")

#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && (__bool_true_false_are_defined)
# undef true
# define true ((bool)(1))
# undef false
# define false ((bool)(0))
#endif

int main(void)
{
    printf("1: %s\n", TypeName(1));
    printf("true: %s\n", TypeName(true));
    printf("false: %s\n", TypeName(false));
}
但是,如果没有重新定义
true
false
的中间位:

1: int
true: int
false: int
这意味着您不能执行
\u通用
功能,例如:

struct Variant * const int32 = variant_create(1);
struct Variant * const boolean = variant_create(true);
所以我的问题是

  • 重新定义代码片段是安全的吗
  • 这是C11标准中的疏忽还是GCC和Clang中的缺陷

    • 这是因为
      stdbool.h
      中的
      true
      false
      只是整数
      1
      0
      ,它们的类型确实是
      int
      ,而不是
      bool

      C11§7.18布尔类型和值
      其余三个宏适用于
      #if
      预处理指令。他们 是

      它扩展为整数常量
      1

      false
      
      它扩展为整数常量
      0
      ,并且

      __bool_true_false_are_defined
      
      它扩展为整数常量
      1


      这两种类型实际上都是宏:

      7.18布尔类型和值

    • 其余三个宏适用于#if预处理指令。
      它们是:
      true,展开为整数常量1,
      false,扩展为整数常量0,

      __bool\u true\u false\u是定义的,扩展为整数常量1
    • 最后一条规则规定允许您重新定义宏:

    • 尽管有7.1.3的规定,程序可能会取消定义,然后 重新定义宏bool、true和false。(259)

      259)见“未来图书馆方向”(7.31.9)

    • 尽管参考了规则:

      7.1.3保留标识符

    • 如果程序删除了(带有#unde)第一行中标识符的任何宏定义 在上面列出的组中,行为未定义
    • 规则7.31.9说重新定义可能不是一个好主意:

      7.31.9布尔类型和值

    • 取消定义宏bool、true和false的功能是 过时的特征

    • 因此,我建议您创建自己的my_true和my_false宏,并将其强制转换为布尔。

      您的问题“这是C11标准中的疏忽还是GCC和Clang中的错误?”的答案是“两者都不是”

      其他人解释了为什么它不是GCC和Clang中的bug


      这也不是标准中的一个疏忽,该标准以向后兼容性的方式定义了真与假。若将true定义为(bool)1,将false定义为(bool)0,则更可能遇到不兼容的宏定义。最明显的影响是警告。如果宏的重新定义(不干预#unde)没有改变定义,编译器通常不会发出警告;因此,最简单的定义是最不可能在野外产生问题。

      C没有比
      int
      更窄的整数类型的文本,正如其他人所说,宏
      false
      true
      因此分别被定义为
      0
      1
      。因此,您为
      \u Bool
      描述的问题对于所有其他窄数据类型都是一样的:在类型泛型宏中很难触发例如
      short
      变量,使用
      'a'
      调用这样的宏也不会触发
      char
      变量

      替换宏不好,因为它们在预处理器
      #if
      表达式中不可用。如果以后包含的某些代码使用它们,编译将失败

      你可以用

      # define true ((_Bool)+1)
      # define false ((_Bool)+0)
      

      相反。小小的加号
      +
      神奇地使预处理器在表达式中将它们解释为
      ((0)+1)
      ((0)+0)
      ,因此它们仍然会做你期望的事情。

      这并不能回答我提出的任何一个问题。我知道
      true
      false
      被定义为整数。我的示例表明,这并不理想,因为
      \u Generic
      的类型推断失败。这两个问题正是我需要回答的。@MattClarkson我是说你得到的是
      int
      ,因为它们确实是
      int
      。结果并不像你在问题中所说的那样不正确。它是由编译器演绎规则定义的正确的,但对于我的用例是不正确的。您可能希望
      true
      作为
      bool
      进行推断。
      __bool_true_false_are_defined
      
      # define true ((_Bool)+1)
      # define false ((_Bool)+0)