【问题标题】:Why doesn't comparison with bool convert to bool in C11?为什么在 C11 中与 bool 比较不转换为 bool?
【发布时间】:2017-11-26 18:54:53
【问题描述】:

给定以下 C11 代码:

int a = 1234;

bool b = (bool)a; // equivalent to (a != 0) or (a != false) which evaluates to 1 or true

if (a) // equivalent to if(a != 0) or if (a != false) which evaluates to 1 or true
  printf("a\n");

if (a == (bool)true) // should be equivalent to if(!(a == false)) or if (a != false)
  printf("a == (bool)true\n");

我知道 true 是 #define true 1,但 bool 显然不是普通的整数类型,因为像 (bool)0.1 这样的东西的计算结果为 1,而转换为 int 会导致 0。

1) 为什么true 没有定义为(bool)1?这将允许编译器至少输出一个警告。

2) 为什么我的示例中的整数没有转换为 bool 以使 a == (bool)true 的计算结果为 (bool)a == (bool)true 这实际上是正确的?

【问题讨论】:

  • 即使它被定义为(bool)1 积分提升仍然会将a == true 变成a == 1 这是错误的。积分提升将始终“提升” bool 和 int,因为那是更广泛的类型。这就是进行促销的意义所在。
  • “为什么我的例子中的整数没有转换成 bool”——因为这不是整数提升在 C 中的工作方式。
  • _Bool 是整数类型,但“编译器使用以下 hack”是不正确的。 This behavior is specified by the Standard
  • bool 是一个真正的布尔类型;布尔变量只能有 rwo 值。但是a 不是布尔变量,它的值也不是布尔的可能性。我看不出有任何理由认为 C 应该选择将 a 转换为 bool 而不是在整数和布尔值之间的比较中将布尔值转换为 int,但无论您是否可以证明这一点选择,这不是 C 的工作方式。同样,在char a = 'A'; 之后,a == 321 的值为 false,即使 a == (char)321 为真。
  • @xnor -- 我不知道您为什么坚持称其为“hack”,而且它肯定不是编译器 hack。 _Bool 的转换在标准 just like all other conversions 中明确描述。 0.123 被转换为非_Bool 的整数类型时会被截断,并带有下划线here in the Standard。

标签: c boolean c11


【解决方案1】:

为什么C11中与bool比较不转成bool?

_Bool 是最低等级,相等运算符== 指定其_Bool 操作数提升为int。 @StoryTeller


_Bool 的等级应小于所有其他标准整数类型的等级。 C11 §6.3.1.1 1

(等式运算符)如果两个操作数都具有算术类型,则执行通常的算术转换。 §6.5.9 4

(通常的算术转换)...整数提升在两个操作数上执行 §6.3.1.8 1

(整数提升)如果 int 可以表示原始类型的所有值 ...该值将转换为 int ... §6.3.1.1 2


OP 的代码示例没有“与 bool 比较”。

// int compared to int: false since a == 1234 and that is not equal 1
if (a == true)  

本来可以有

// int compared to _Bool: false since a == 1234 and that is not equal to 0 or 1
if (a == b) 

对于int == _Bool、int == short、int == signed char,同样的事情也会发生。较低等级的操作数被提升为int。


1) 为什么不将 true 定义为 (bool)1?这将允许编译器至少输出一个警告。

为什么?多年前的标准委员会决定。在引入_Bool 时,将true 视为(int)1 而不是(_Bool)1 对现有代码的影响肯定会更小。 (C99)。这与其他子int 常量如SHRT_MAX 一致,通常是int,而不是short。在任何情况下,在大多数情况下,在进一步处理之前都会发生对int/unsigned 的提升——就像在这个比较案例中一样。

不需要进一步的(_Bool)1 来允许编译器提供警告。可以使用各种分析工具制作一个提供警告的编译器。正如(_Bool)1,它会简化编译器提供这样一个警告的事情。

2) 为什么我的示例中的整数没有转换为 bool 以使 a == true 的计算结果为 (bool)a == true 这实际上是正确的?

由于true 是(int)1,与a == true,两个操作数都是int。 _Bool 不适用于此处。

2) [OP 更新] 为什么我的示例中的整数没有转换为 bool,以至于 a == true 的计算结果为 (bool)a == true,这实际上是正确的?

答案的顶部解决了这个问题:int 中的true,因此在比较之前(bool)a 被提升为int,因为int 的排名高于_Bool。

【讨论】:

  • 我已将 (bool) 强制转换为 true 以阐明示例的意图。看起来很愚蠢..
  • 在将int 与1 进行比较时,编译器如何发出警告,而true 在预处理器完成其工作后被替换为true?还是您的意思是在预处理之前?
  • @xnor "true 扩展为整数常量 1" C11 §7.18 3,其中可能包括 #define true (/* special_syntax */ 1) 并且编译器使用该 special_syntax 进行诊断寻找。或#define true 000000000000001 以获得类似的效果。编译器程序员是一群鬼鬼祟祟的人。
  • 当然,使用不同的 #define,但 stdbool.h 被标准化为“扩展为整数文字 1。”
  • @xnor “标准化以扩展为整数文字 1。”是一个可疑的引用,因为 C 在 C 规范中的任何地方都没有“整数文字”。你的来源是什么?
【解决方案2】:

我知道 #define true 1 是真的,但 bool 显然不是 普通整数类型,因为像 (bool)0.1 这样的东西的计算结果为 1 而转换为 int 会导致 0。

bool(实际上_Bool;bool是一个扩展为_Bool的宏)是一个整数类型。它确实有一个不寻常的特性,它不与任何其他类型共享:将任何非零值转换为 _Bool 会产生 1。

请注意,产生逻辑布尔值的运算符仍会产生 int 结果,其值为 0 或 1。由于隐式转换,这通常不是问题。

1) 为什么不将true 定义为(bool)1?这将允许编译器 至少输出一个警告。

编译器可以随时生成警告。与true 或false 进行比较时发出警告是个好主意。

2) 为什么我的例子中的整数没有转换成bool 这样的 a == true 将评估为 (bool)a == true 这实际上会 是真的吗?

a == true 必须先将其操作数转换为相同类型,然后才能进行比较。这是通过通常的算术转换完成的。规则(相当复杂)在N1570 第 6.3.1.8 节中进行了描述。一个非常快速且不精确的总结是,较窄类型(较小的整数转换等级)的操作数被转换为另一个操作数的类型。例如,当您比较 int 和 long 类型的表达式时,int 操作数将提升为 long。 _Bool 是最窄的整数类型,因此它总是在比较中提升,除非它与另一个 _Bool 值进行比较。

仅为_Bool 更改这些规则会令人困惑,而且真的不会给您带来太多收益。

底线:不要将相等的值与false 或true 进行比较。不要写:

if (a == true)

只写:

if (a)

如果这就是你的意思。同样,不要写:

if (a == false)

随便写

if (!a)

【讨论】:

  • "除非它与另一个 _Bool 值进行比较。"是有问题的。 Even 都是 _Bool,整数提升在两个操作数 C11 §6.3.1.8 1 上执行。所以两者都在 == 之前变为 int。当然,这些对_Bool 的促销不会造成功能上的差异。
  • "编译器可以随时生成警告。"好吧,当您将 int 与 true 进行比较时,如果它被定义为整数 1 .. 就不会发出警告,现在就是这种情况。
  • @xnor:是的,编译器可能会发出这样的警告。它必须跟踪常量1 源自宏true 的扩展这一事实。由于预处理器是编译器的一部分,所以没有什么特别的原因不能这样做。
【解决方案3】:

来自cmets的总结:

_Bool 实际上“只是”另一种无符号整数类型,其例外规则是,如果值不等于 0(“false”),则转换为它总是导致 1(“true”)。

因为它是无符号整数,所以适用整数提升规则。 即使true 被定义为(bool)1,比较a == true 的结果实际上是比较1234 == 1,它始终是false。

【讨论】:

  • 请注意,即使在将x == true 定义为将x 转换为布尔值的语言中,编写== true 仍然被认为是糟糕的风格
  • _Bool 是一个真正的布尔类型。看来您对_Bool 和其他整数类型之间的比较行为很感兴趣。这是 C 比较规则的属性,而不是 _Bool 类型的属性。
  • 您最后的评论令人费解,这就像说汽车是摩托车,只是增加了 2 个轮子。事实上_Bool 是一个真正的布尔类型。 (这与整数类型并不互斥)。您甚至指出了真正布尔类型的关键定义属性之一,即唯一的状态是零和非零。
  • exceptional rule 和 this 与 a == true 的关系不清楚。这不是使用a == true 或if(a == true) 转换为_Bool。问题中的唯一转换(除了(bool)a))是从_Bool 到int。
  • "它也可以是 uint8_t 的别名" -- _Bool 是一个内置类型,不能作为其他类型的别名。 _Bool must have a conversion rank less than that of all other standard integer types.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-22
相关资源
最近更新 更多