3

我正在从 K&R 学习 C 并且在本书的第 4.4 部分中提到范围规则时感到困惑。在我继续之前,让我发布我正在处理的源文件。

#include <stdio.h>

void first(void);

int main(void) {
    printf("In main.\n");

    first();
    second();

    return 0;
}

void first(void) {
    printf("In first.\n");
}

void second(void) {
    printf("In second.\n");
}

现在,除非我比我想象的更愚蠢,否则这本书给了我这样的想法:函数原型(在与函数定义相同的文件中)是出于范围界定的原因而存在的。也就是说,它们的存在是为了允许在编译文件的顶部声明函数,以便提前通知源文件的其余部分是否存在“对象”(如果我可以这样称呼它)。

我对上述代码的问题是在我正在使用GCC version 4.7.1上述文件的 Arch Linux 虚拟机中无法编译并给出以下错误:conflicting types for second.

但是,当在我的物理机器上运行相同的代码时,运行Ubuntu 12.04GCC 版本 4.6.3,它编译得很好。

我的问题是:这是编译器功能吗?second因为如果不是,我很惊讶它完全可以编译,因为,没有函数原型main(如果我理解正确的话)不应该知道second' 的存在。

4

1 回答 1

5

发生“冲突类型”错误消息是因为大多数 C 编译器在遇到尚未声明的函数时,将隐式声明该函数的原型并返回 int。所以当在second()中遇到时main(),GCC 4.7.1 会推断出以下定义:

int second();

然后当编译器到达函数定义时,注意到推断的原型的签名与定义的签名不匹配,并因错误而中止。

至于为什么4.6.3能成功编译这段代码,下面是猜测。GCC 4.6.3 可能有一些错误(或特性,由您决定)允许函数实现与其原型的返回类型不同。由于 C 允许具有非 void 返回类型的函数终止而不返回任何内容(这使得它们的返回值未定义),这可能只是两个次优事物相互抵消的情况。

(4.6.3 中的行为也可能是版本之间默认编译器选项的更改,或者您可能正在使用不同的选项调用编译器。)

于 2012-10-09T17:06:52.887 回答