C11_Generic将true和false推断为整数

时间:2015-01-09 11:36:54

标签: c generics c11

在C11中,_Generic宏可以允许很酷的通用功能。但是,使用truefalse会导致正常情况下的错误扣除:

#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));
}

打印:

1: int
true: bool
false: bool

但是没有重新定义truefalse的中间位:

1: int
true: int
false: int

这意味着您无法执行_Generic功能,例如:

struct Variant * const int32 = variant_create(1);
struct Variant * const boolean = variant_create(true);

所以我的问题是

  • 重定义代码段是安全的吗?
  • 这是C11标准中的疏忽还是GCC和Clang中的错误?

4 个答案:

答案 0 :(得分:8)

两种类型都是宏:

  

7.18布尔类型和值

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

最后一条规则说您可以重新定义宏:

  
      
  1. 尽管有7.1.3的规定,但程序可能会取消定义,也可能取消定义   重新定义宏bool,true和false。 259)

         

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

  2.   

尽管引用了规则:

  

7.1.3保留标识符

     
      
  1.   如果程序删除(使用#undef)第一个标识符的任何宏定义   上面列出的组,行为未定义。
  2.   

规则 7.31.9 表示重新定义可能不是一个好主意:

  

7.31.9布尔类型和值

     
      
  1.   取消定义然后重新定义宏bool,true和false的能力是   一个过时的功能。
  2.   

所以我建议你创建自己的my_true和my_false宏,这些宏被转换为_Bool。

答案 1 :(得分:4)

那是因为true中的falsestdbool.h只是整数10,它们的类型确实是int,而不是{{} 1}}。

  

C11§7.18布尔类型和值bool

     

其余三个宏适用于<stdbool.h>预处理指令。他们   是

#if
     

扩展为整数常量true

1
     

扩展为整数常量false

0
     

扩展为整数常量__bool_true_false_are_defined

答案 2 :(得分:2)

C对于比int窄的整数类型没有文字,而且正如其他人所说的那样,宏falsetrue因此被定义为0并且分别为1。因此,您为_Bool描述的问题对于所有其他窄数据类型是相同的:很难在类型通用宏中触发例如short变体,并且使用{{1调用这样的宏}}也不会触发'A'变体。

您的替换宏不合适,因为它们在预处理器char表达式中不可用。如果之后包含的某些代码使用它们,则编译将失败。

您可以使用

#if

代替。小加# define true ((_Bool)+1) # define false ((_Bool)+0) 符号神奇地使预处理器在表达式中将它们解释为+((0)+1),因此它们仍然可以达到预期效果。

答案 3 :(得分:0)

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

其他人已经解释了为什么它不是GCC和Clang中的错误。

这也不是标准中的疏忽,它以向后兼容性的方式定义 true false 。如果 true 被定义为(bool)1 false 被定义为(bool)0 ,则更有可能遇到不兼容的宏定义。最明显的效果是警告。如果重新定义宏(不介入#undef)不改变定义,编译器通常不会发出警告;因此,最简单的定义是最不可能在野外提出问题。