很久以前,我在一个论坛上偶然发现了一个有趣的问题,我想知道答案。
考虑以下C函数:
f1.c
#include <stdbool.h>
bool f1()
{
int var1 = 1000;
int var2 = 2000;
int var3 = var1 + var2;
return (var3 == 0) ? true : false;
}
从
false
开始,这应该始终返回var3 == 3000
。 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。但是编译并运行它之后,也会显示执行:$ gcc main.c f1.c -o test
$ ./test
false
executed
这是为什么?此代码是否具有某种未定义的行为?
注意:我用
gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2
编译了它。 最佳答案
如其他答案所述,问题是您使用的gcc
没有设置编译器选项。如果执行此操作,则默认为所谓的“gnu90”,这是从1990年撤消的旧C90标准的非标准实现。
在旧的C90标准中,C语言存在一个主要缺陷:如果您在使用函数之前未声明原型(prototype),则默认为int func ()
(其中( )
表示“接受任何参数”)。这会更改函数func
的调用约定,但不会更改实际的函数定义。由于bool
和int
的大小不同,因此在调用函数时,代码将调用未定义的行为。
随着C99标准的发布,这种危险的废话行为在1999年得到了解决。隐式函数声明被禁止。
不幸的是,默认情况下,版本5.x.x之前的GCC仍使用旧的C标准。也许没有理由为什么要将代码编译为标准C以外的任何内容。因此,您必须明确告诉GCC它应该将代码编译为现代C代码,而不是使用25年以上的非标准GNU废话。
通过始终将程序编译为以下方式解决此问题:
gcc -std=c11 -pedantic-errors -Wall -Wextra
-std=c11
告诉它根据(当前)C标准(非正式地称为C11)进行全心全意的尝试。 -pedantic-errors
告诉它全心全意地执行上述操作,并在编写违反C标准的错误代码时给出编译器错误。 -Wall
的意思是给我一些额外的警告,可能会比较有用。 -Wextra
的意思是给我一些其他的警告,可能会比较有用。 关于c - 此C函数应始终返回false,但不返回,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36476178/