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

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

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的调用约定,但不会更改实际的函数定义。由于boolint的大小不同,因此在调用函数时,代码将调用未定义的行为。

随着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/

    10-11 23:20
    查看更多