8

任何人都知道为什么会在 C 中成功编译?

int main(){
     display();
   return 0;
 } 

 void display(){
     printf("Why am I compiling successfully?");
 }

我认为当没有提供声明时 C 假设extern int Function_name(arg1,arg2,...){}.因此这应该会给出一个错误,但是它正在工作!我知道 Ideone 正在压制警告,但我的问题是为什么它没有给出直接错误?(但是在 C++ 中这是直接错误)

4

5 回答 5

8

在编译器中调高警告级别,您应该会收到 2 个警告,

display未声明,int假定

display重新声明

编辑:

旧版本的 C(C99 之前)并不真正关心返回类型或参数类型。您可以说这是 K&R 遗产的一部分。例如,如果您没有明确指定参数类型,编译器根本不会检查它们。

C++ 更严格,IMO 是一件好事。当我用 C 编码时,我总是提供声明并指定参数列表。

于 2012-11-19T12:52:11.160 回答
5

它正在编译,因为 C 使用许多默认值来向后兼容。在 K&R C 中,您无法指定函数原型,因此编译器只会假设您在调用函数时知道自己在做什么。

后来(至少是 ANSI C,但甚至可能在 C99 中),C 真的没有办法区分

void display(void);
void display();

所以空声明也必须被接受。

这就是为什么您display()无需先定义就可以调用的原因。

printf()很相似。如果您忘记了,您将收到链接器错误,-lc但从编译器的角度来看,代码“足够好”。

一旦您启用编译器必须提供的所有警告,这种情况就会发生变化,并且当您禁用 K&C 兼容性或启用严格的 ANSI 检查时,它将因错误而失败。

这就是为什么在“如何使用任何编程语言射中自己的脚”之类的列表中,“C”经常被列为“你射中自己的脚” 。

于 2012-11-19T12:53:34.110 回答
3

这取决于您的 Cx (C89, C90, C99,...)

对于函数返回值,在 C99 之前明确规定,如果没有可见的函数声明,则翻译器提供一个。这些隐式声明默认返回类型为 int

来自C 标准的理由(6.2.5 第 506 页)

在 C90 之前,没有函数原型。开发人员希望能够交换具有相同整数类型的有符号和无符号版本的参数。如果函数定义中的参数类型具有不同的符号,则必须强制转换参数,这被视为与 C 的简单类型检查系统背道而驰,并且有点侵入性。原型的引入并没有完全消除论点可互换性的问题。省略号表示对 1590 省略号一无所知,不提供预期参数类型的信息。类似地,对于函数返回值,在 C99 之前明确规定,如果没有可见的函数声明,则翻译器提供一个。这些隐式声明默认返回类型为 int 。如果实际函数碰巧返回类型 unsigned int ,那么这样的默认声明可能会返回意外结果。许多开发人员对函数声明的态度很随意。我们其他人不得不忍受委员会不想破坏他们编写的所有源代码的后果。函数返回值的可互换性现在是一个争论点,因为 C99 要求函数声明在调用点可见(不再提供默认声明)

于 2012-11-19T13:13:29.137 回答
1

它可能确实如此(假设您编写了这样的声明),但是由于您没有传递参数,因此它可以正常工作。就像你声明int main()它应该在哪里一样int main(int argc, char *argv[])

因此,如果您尝试传递一些参数(与默认参数不同),main然后使用它们display可能会失败。

顺便说一句,对我来说它可以编译,但会产生警告:

$ gcc z.c
z.c:8:6: warning: conflicting types for ‘display’ [enabled by default]
z.c:4:5: note: previous implicit declaration of ‘display’ was here
于 2012-11-19T12:57:12.677 回答
0

当我使用 gcc 编译时,我会收到有关重新声明 的警告display,正如您所期望的那样。

你收到警告了吗?

它可能会“运行”,因为 C 不会破坏函数名称(如 C++)。所以链接器寻找一个符号“显示”并找到一个。链接器使用该地址运行display。我希望结果不会像您一直期望的那样。

于 2012-11-19T12:54:45.333 回答