C11_泛型将真和假推断为整数
在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__
\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)