很久以前,我在一个论坛上偶然发现了一个有趣的问题,我想知道答案。
考虑下面的C函数:
f1.c
#include <stdbool.h>
bool f1()
{
int var1 = 1000;
int var2 = 2000;
int var3 = var1 + var2;
return (var3 == 0) ? true : false;
}
从var3 == 3000
开始,这应该总是返回false
。main
函数如下所示:
main.c
#include <stdio.h>
#include <stdbool.h>
int main()
{
printf( f1() == true ? "true\n" : "false\n");
if( f1() )
{
printf("executed\n");
}
return 0;
}
因为f1()
应该总是返回false
,所以可以预期程序只会在屏幕上打印一个false。但编译运行后,也会显示executed:
$ gcc main.c f1.c -o test
$ ./test
false
executed
为什么会这样呢?这段代码是否有某种未定义的行为?
注意:我是用gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2
编译的。
发布于 2016-04-09 17:24:10
我认为Lundin的优秀答案中提到的大小不匹配实际上发生在哪里,这是很有趣的。
如果使用--save-temps
进行编译,您将获得可以查看的程序集文件。下面是f1()
执行== 0
比较并返回其值的部分:
cmpl $0, -4(%rbp)
sete %al
返回的部分是sete %al
。在C的x86调用约定中,通过寄存器%eax
返回小于或等于4个字节的返回值(包括int
和bool
)。%al
是%eax
的最低字节。因此,%eax
的高3个字节处于不受控制的状态。
现在在main()
中
call f1
testl %eax, %eax
je .L2
这将检查整个%eax
是否为零,因为它认为它正在测试一个int。
添加显式函数声明会将main()
更改为:
call f1
testb %al, %al
je .L2
这就是我们想要的。
发布于 2016-04-07 20:37:06
请使用如下命令进行编译:
gcc -Wall -Wextra -Werror -std=gnu99 -o main.exe main.c
输出:
main.c: In function 'main':
main.c:14:5: error: implicit declaration of function 'f1' [-Werror=impl
icit-function-declaration]
printf( f1() == true ? "true\n" : "false\n");
^
cc1.exe: all warnings being treated as errors
有了这样的消息,您应该知道如何纠正它。
编辑:在阅读了一条(现已删除的)注释后,我尝试在不使用标志的情况下编译您的代码。好吧,这导致了链接器错误,没有编译器警告,而不是编译器错误。而且这些链接器错误更难理解,所以即使-std-gnu99
不是必需的,请始终尝试至少使用-Wall -Werror
,这将为您省去很多麻烦。
https://stackoverflow.com/questions/36476178
复制相似问题