小编典典

这个 C 函数应该总是返回 false,但它不会

all

很久以前在一个论坛里偶然发现一个有趣的问题,我想知道答案。

考虑以下 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函数如下所示:

主程序

#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 。 但是编译运行之后,也显示 执行了:

$ gcc main.c f1.c -o test
$ ./test
false
executed

这是为什么?这段代码是否有某种未定义的行为?

注意:我用gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2.


阅读 80

收藏
2022-04-11

共1个答案

小编典典

如其他答案中所述,问题在于您gcc在未设置编译器选项的情况下使用。如果您这样做,它会默认使用所谓的“gnu90”,这是从 1990 年起取消的旧 C90
标准的非标准实现。

在旧的 C90 标准中,C 语言存在一个重大缺陷:如果您在使用函数之前没有声明原型,它将默认为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告诉它半心半意地尝试根据(当前)C 标准(非正式地称为 C11)进行编译。
  • -pedantic-errors告诉它全心全意地执行上述操作,并在您编写违反 C 标准的错误代码时给出编译器错误。
  • -Wall意味着给我一些额外的警告,这些警告可能会很好。
  • -Wextra意味着给我一些其他可能很好的额外警告。
2022-04-11