布尔转整数的转换

177

这种转换有多可移植?我能确信两个断言都会通过吗?

int x = 4<5;
assert(x==1);

x = 4>5;
assert(x==0);

不要问为什么。我知道它很丑。谢谢。


1
为什么不改变第一个表达式呢?你可以写成 assert(x!=0)。即使 bool(true) 可以转换为 int(1),"not false" 的断言表达式更易读。 - harper
2
为什么不使用 assert(4 < 5);assert(!(4 > 5)); 呢? - Martin York
4
使用比较表达式中所需的值是完全合理的。 - R.. GitHub STOP HELPING ICE
4
如果我真的需要将布尔值转换为0或1,我可能会写(4 < 5) ? 1 : 0。一个好的编译器可能会产生相同的机器代码,而且对于人类读者来说更清晰。 - ollb
显示剩余3条评论
4个回答

268
int x = 4<5;
完全可移植。符合标准。`bool` 到 `int` 的转换是隐式的!
来自 C++11 或 C++14 标准的 §4.7/4,C++17 标准的 §7.8/4,以及 20 标准的 §7.3.9/2 均说明(整数转换):
如果源类型为 `bool`,那么值false转换为零,而值true转换为一
对于 C 来说,在 1999 年之前我所知道的是没有 `bool` 类型。因此,`bool` 到 `int` 的转换仅在 C++ 中相关。在 C 中,`4<5` 求值为 `int` 值,此时该值为 `1`,`4>5` 求值为 `0`。
编辑:Jens 在评论中提到,C99 有 `_Bool` 类型。`bool` 是在 `stdbool.h` 头文件中定义的宏。`true` 和 `false` 也被定义为在 `stdbool.h` 中的宏。
来自 C99 的 §7.16 表明:
bool 展开为 _Bool。 [..] 展开为整数常量1的true和展开为整数常量0的false,[..]

14
无论是哪个版本的C语言以及bool/_Bool类型是否可用,在C语言中,关系运算符产生的结果是int类型,而不是bool类型。也就是说,即使在C99中,关系运算符仍然产生int类型的结果。 - AnT stands with Russia
无论隐式布尔->整数转换是否在标准中,与未经转换使用的实际类型相比,在代码中实际使用时可能会更加混淆。 - Smar

60
你同时标记了问题[C]和[C++]。结果在两种语言之间是一致的,但是答案的结构在这两种语言中是不同的。
在C语言中,你的示例与bool没有任何关系(C99也适用)。在C语言中,关系运算符不会产生bool结果。例如,“4>5”和“4<5”都是表达式,它们产生类型为int的结果,其值为0或1。因此,在你的C语言示例中没有进行任何形式的“bool到int转换”。
在C++中,关系运算符确实产生bool结果。bool值可以转换为int类型,true转换为1,false转换为0。这由语言保证。
另外,C语言也有专门的布尔类型_Bool(宏别名为bool),其整数转换规则基本上与C ++相同。但是,这与你在C中特定的示例无关。再次强调,在C中,关系运算符始终产生int(而不是bool)结果,无论语言规范的版本如何。

2
没错,在K&R C中没有bool类型。我将我的问题重新标记为C99。 - pic11
4
不,你没明白。在C语言中,包括C99,在比较运算符的结果是一个“int”,而不是“bool”。不会发生任何转换 - R.. GitHub STOP HELPING ICE
有没有符合标准的方式,可以让一种语言拥有像 bool 一样的类型,但不允许其地址被取出?许多嵌入式系统使用这种类型(通常使用标识符 bit 声明)。例如,在中等范围的 PIC 上,if (bitVar1) bitVar2=1; 将是两个指令;而 if (byteVar1) byteVar2=1; 的最佳编码至少需要四个指令(在许多编译器上可能需要五个)。因此,这种类型可以提供重大的性能提升。 - supercat
@supercat:您能详细说明一下如何用比“字节”版本更少的指令实现“位”版本吗?在现代x84平台上,“字节”版本可以轻松地用两个指令实现:cmpsetz(或类似的指令,具体取决于byteVar1存储的位置)。此外,如果有关于byteVar1值的额外信息可用,则可能会进行额外的优化。 - AnT stands with Russia
@AndreyT:在一款中档的PIC上,如果bitvar1是地址0x12的第3位,而bitvar2是地址0x45的第6位,则指令序列if (bitvar1) bitvar2=1将是btfsc 0x12,3; 如果地址0x12的第3位未设置,则跳过下一条指令,然后是bsf 0x45,6; 设置地址0x45的第6位。使用这些地址的字节,最短的可能序列是:movf 0x12,w; 将W加载为值并设置Z标志(如果为零)movlw 0x01; 加载W为1而不影响Zbtfss 3,2; 如果Z标志设置,则跳过下一条指令movwf 0x45; 将W存储到地址0x45 - supercat
显示剩余3条评论

18

C标准的第6.5.8.6节规定:

如果指定的关系为真,则小于运算符<,大于运算符>,小于等于运算符<=和大于等于运算符>=中的每个运算符都应返回1,如果指定的关系为假,则返回0。结果的类型为int。


感谢提供参考。看起来true==1是出于历史原因。 - pic11

3

由于int到bool的强制转换是隐式进行的,因此似乎没有问题。这适用于Microsoft Visual C++、GCC和Intel C++编译器。在C或C++中都没有问题。


2
“它在某些情况下有效”不是检查正确性的好方法,特别是在那些工具未指定版本的情况下。我更喜欢其他答案中的方法; 它们不能保证特定实现是正确的,但它们可以保证正确实现会做什么。 - Matthew Read

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接