(bool)转换是否可靠,始终为0或1?

4
从一些Stack Overflow的阅读资料我了解到在stdbool.h中定义的bool是一个宏,它展开成内置类型_Bool,而true被定义为1false被定义为0强制转换为bool是否保证返回值为01_Bool变量(包括转换后的rvalues)有可能达到除01之外的其他值吗? 下面的代码暗示_Bool变量(包括转换后的rvalues)只会有01的值,但我想确认这是被保证的,并且我没有观察到特定于目标或编译器版本的行为。
(顺便说一句,我最关心的是确认只有将NULL转换为_Bool时才会是0,将所有其他可能的指针值转换为_Bool时都会是1
$ cat ./main.c
#include <stdio.h>
#include <stdbool.h>

int main( int argc, char* argv )
{
  int   i;
  int*  p = &i;
  int*  n = NULL;

  printf( "%zu\n", sizeof( (bool)p ) );
  printf( "%p - %d\n", p, (bool)p );
  printf( "%p - %d\n", n, (bool)n );
  printf( "%d\n", (bool)3 );

  return 0;
}

$ gcc --version
gcc (GCC) 8.2.1 20181215 (Red Hat 8.2.1-6)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcc -g ./main.c && ./a.out    
1
0x7ffdac3290bc - 1
(nil) - 0
1

@AlexLop。- 是的,谢谢。我认为我已经尽了查找相关现有帖子的职责,但我想可能已经有答案了。仍然感激现有的答案。 - StoneThrow
2个回答

3

C 2018 6.3.1.2 1说:

当任何标量值被转换为_Bool类型时,如果该值与0相等,则结果为0;否则,结果为1。


我认为我意识到了一个有趣的边界情况:我记得很久以前学过,尽管 NULL 几乎肯定是 0,但并不保证。在这种情况下,(bool)NULL 将评估为 1,只有非 NULL 指针 0x0 在转换为 bool 时才会评估为 0 - StoneThrow
1
@StoneThrow:如果一个指针是空指针,包括NULL,它与0相等,不管C实现如何表示空指针。 - Eric Postpischil
@StoneThrow:这是错误的。将bool转换的结果是0还是1与空指针的表示方式无关。如果指针为空,则为0,如果指针不为空,则为1。 - R.. GitHub STOP HELPING ICE
@StoneThrow "(bool)NULL would evaluate to 1" 是可能的(当 NULL 是某个非零整数时)。(bool)non_null_pointer 总是评估为值为1 - 不管 NULL 如何定义。 - chux - Reinstate Monica
让我们在聊天中继续这个讨论 - chux - Reinstate Monica
显示剩余5条评论

2
是的,将类型转换为bool保证会产生0或1,在未定义的行为限制范围内可以产生任何结果。如果在转换为bool之前存在未定义的行为,则可能会观察到奇怪的现象,因为编译器可能会基于不再有效的假设进行变换。例如,如果实现在存储时将其折叠为0/1,则在从内存加载bool时,它可能假设该值已经是0或1,并且不需要进一步折叠。如果通过缓冲区溢出、别名侵犯等方式改变了bool对象的存储,则可能会看到不同的值。

1
这是一个相当广泛的免责声明。它适用于任何事情。 * 乘法运算,除非在此之前存在未定义的行为。 printf 打印,除非在此之前存在未定义的行为... - Eric Postpischil
1
@EricPostpischil:确实如此,但我觉得需要在这里说一下,因为很多语言的用户并不真正理解未定义行为是什么意思,如果您还没有对UB有直觉,从一个“不能有其他值”的对象中读取除0或1之外的值确实非常令人惊讶。 - R.. GitHub STOP HELPING ICE

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