很久以前在一个论坛里偶然发现一个有趣的问题,我想知道答案。
考虑以下 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函数如下所示:
false
var3 == 3000
main
#include <stdio.h> #include <stdbool.h> int main() { printf( f1() == true ? "true\n" : "false\n"); if( f1() ) { printf("executed\n"); } return 0; }
由于f1()应该总是 return false,人们会期望程序只在屏幕上打印一个 false 。 但是编译运行之后,也显示 执行了:
f1()
$ gcc main.c f1.c -o test $ ./test false executed
这是为什么?这段代码是否有某种未定义的行为?
注意:我用gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2.
gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2
如其他答案中所述,问题在于您gcc在未设置编译器选项的情况下使用。如果您这样做,它会默认使用所谓的“gnu90”,这是从 1990 年起取消的旧 C90 标准的非标准实现。
gcc
在旧的 C90 标准中,C 语言存在一个重大缺陷:如果您在使用函数之前没有声明原型,它将默认为int func ()(其中的( )意思是“接受任何参数”)。这会改变函数的调用约定func,但不会改变实际的函数定义。由于 和 的大小bool不同int,因此您的代码在调用函数时会调用未定义的行为。
int func ()
( )
func
bool
int
随着 C99 标准的发布,这种危险的胡说八道行为在 1999 年得到了修复。隐式函数声明被禁止。
不幸的是,直到 5.xx 版的 GCC 默认仍使用旧的 C 标准。您可能没有理由将您的代码编译为标准 C 之外的任何东西。所以您必须明确告诉 GCC 它应该将您的代码编译为现代 C 代码,而不是一些 25 年以上的非标准 GNU 废话.
通过始终将程序编译为:
gcc -std=c11 -pedantic-errors -Wall -Wextra
-std=c11
-pedantic-errors
-Wall
-Wextra