gpt4 book ai didi

c - 使用 GCC 和 bool 指针的条件运算符的奇怪结果

转载 作者:太空狗 更新时间:2023-10-29 16:29:13 25 4
gpt4 key购买 nike

在下面的代码中,我将 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.cuser@host:~$ ./a.out 123

特别烦人的是 victim() 函数实际上在库中,如果值大于 1 就会崩溃。

转载于 GCC 版本 4.8.2-19ubuntu1 和 4.7.2-5。未在 clang 上转载。

最佳答案

当 GCC 编译该程序时,汇编语言输出包括序列

movzbl (%rax), %eax
movzbl %al, %eax
movl %eax, -4(%rbp)

它执行以下操作:

  1. *foo(在汇编中用(%rax)表示)复制32位到寄存器%eax,并填入高位-用零对 %eax 的位进行排序(不是说有任何位,因为 %eax 是一个 32 位寄存器)。
  2. 复制%eax的低8位(用%al表示)到%eax,并填入高位%eax 的位为零。作为 C 程序员,您会将其理解为 %eax &= 0xff
  3. %eax的值复制到%rbp上面4个字节,也就是bar在栈上的位置。

所以这段代码是汇编语言的翻译

int bar = *foo & 0xff;

显然,GCC 已根据 bool 不应包含 0 或 1 以外的任何值这一事实优化了该行。

如果把C源中的相关行改成这样

int bar = *((int*)foo) ? 1 : 0;

然后程序集变为

movl (%rax), %eax
testl %eax, %eax
setne %al
movzbl %al, %eax
movl %eax, -4(%rbp)

它执行以下操作:

  1. *foo(在汇编中用(%rax)表示)复制32位到寄存器%eax
  2. 针对自身测试 %eax 的 32 位,这意味着将其与自身进行“与”运算,并根据结果在处理器中设置一些标志。 (这里不需要 ANDing,但是没有简单地检查寄存器和设置标志的指令。)
  3. 如果与操作的结果为 0,则将 %eax(由 %al 表示)的低 8 位设置为 1,否则设置为 0。
  4. 复制%eax的低8位(用%al表示)到%eax,并填入高位%eax 的位为零,如第一个片段中所示。
  5. %eax的值复制到%rbp上面4个字节,也就是bar在栈中的位置;也和第一个片段一样。

这实际上是对C代码的忠实翻译。事实上,如果您将强制转换添加到 (int*) 并编译并运行该程序,您会看到它确实输出了 1

关于c - 使用 GCC 和 bool 指针的条件运算符的奇怪结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27661768/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com