【发布时间】:2015-02-24 00:57:05
【问题描述】:
在下面的代码中,我将memset() 一个stdbool.h bool 变量值123。 (也许这是未定义的行为?)然后我将指向该变量的指针传递给受害函数,该受害函数尝试使用条件操作来防止意外值。但是,出于某种原因,GCC 似乎完全删除了条件操作。
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
void victim(bool* foo)
{
int bar = *foo ? 1 : 0;
printf("%d\n", bar);
}
int main()
{
bool x;
bool *foo = &x;
memset(foo, 123, sizeof(bool));
victim(foo);
return 0;
}
user@host:~$ gcc -Wall -O0 test.c
用户@主机:~$ ./a.out
123
让这特别烦人的是victim()函数实际上是在一个库中,如果值大于1就会崩溃。
在 GCC 版本 4.8.2-19ubuntu1 和 4.7.2-5 上转载。未在 clang 上复制。
【问题讨论】:
-
来自 C99 标准:6.5.2 2 声明为 _Bool 类型的对象大到足以存储值 0 和 1。
-
通过将
x定义为bool,您已经向编译器承诺您只会在其中存储0或1。通过将123存储在x1 中,您对编译器撒了谎。 “如果你对编译器撒谎,它就会报仇雪恨。” ——亨利·斯宾塞 -
@SeverinPappadeux:是的,但由于任何非位域对象必须至少为
CHAR_BIT位(和CHAR_BIT >= 8),它也足够大以容纳123的值。您不会因为bool的大小而将其存储在bool对象中,但这是未定义的行为。 -
由于包含了
<stdbool.h>标头,您可以考虑仅使用true和false值(就像在Pascal 中使用Boolean类型一样)。它会使您的代码更具可读性,并使您远离其他值。 -
@MSalters:一些位模式可以是陷阱表示;访问具有这种表示形式的对象(通过适当类型的左值)会导致未定义的行为。
_Bool的规则以我目前懒得探索的方式使事情变得混乱。底线:在_Bool对象中存储除0和1之外的值是应避免的事情。
标签: c gcc undefined-behavior conditional-operator