在C11中,_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));
}
打印:
1: int
true: bool
false: bool
但是没有重新定义true
和false
的中间位:
1: int
true: int
false: int
这意味着您无法执行_Generic
功能,例如:
struct Variant * const int32 = variant_create(1);
struct Variant * const boolean = variant_create(true);
所以我的问题是:
答案 0 :(得分:8)
两种类型都是宏:
7.18布尔类型和值
- 其余三个宏适用于#if预处理指令。
醇>
它们是:
true ,它扩展为整数常量1,
false 扩展为整数常量0,
和
__ bool_true_false_are_defined ,扩展为整数常量1。
最后一条规则说您可以重新定义宏:
- 醇>
尽管有7.1.3的规定,但程序可能会取消定义,也可能取消定义 重新定义宏bool,true和false。 259)
259)参见“未来图书馆方向”(7.31.9)
尽管引用了规则:
7.1.3保留标识符
- 如果程序删除(使用#undef)第一个标识符的任何宏定义 上面列出的组,行为未定义。
醇>
规则 7.31.9 表示重新定义可能不是一个好主意:
7.31.9布尔类型和值
- 取消定义然后重新定义宏bool,true和false的能力是 一个过时的功能。
醇>
所以我建议你创建自己的my_true和my_false宏,这些宏被转换为_Bool。
答案 1 :(得分:4)
那是因为true
中的false
和stdbool.h
只是整数1
和0
,它们的类型确实是int
,而不是{{} 1}}。
C11§7.18布尔类型和值
bool
其余三个宏适用于
<stdbool.h>
预处理指令。他们 是#if
扩展为整数常量
true
,1
扩展为整数常量
false
和0
扩展为整数常量
__bool_true_false_are_defined
。
答案 2 :(得分:2)
C对于比int
窄的整数类型没有文字,而且正如其他人所说的那样,宏false
和true
因此被定义为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)不改变定义,编译器通常不会发出警告;因此,最简单的定义是最不可能在野外提出问题。