为什么#include <stdio.h>不需要使用printf()?

会议logging:

>type lookma.c int main() { printf("%s", "no stdio.h"); } >cl lookma.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. lookma.c Microsoft (R) Incremental Linker Version 8.00.50727.762 Copyright (C) Microsoft Corporation. All rights reserved. /out:lookma.exe lookma.obj >lookma no stdio.h 

在严格的合规模式(意思是“理论上”)中,如果调用一个函数,该函数接受可变数量的参数,而没有函数的原型声明,则调用未定义的行为(这是不好的)。 这意味着编译器可以使用printf()而不使用#include <stdio.h>的原型或等价的声明来执行任何它喜欢的操作。 “任何喜欢的东西”都包括正确的作为选项之一; 这似乎是你的榜样select的选项。

实际上,即使没有printf()函数的正式声明,代码也可以用大多数实际的编译器工作。

正如qrdl所指出的那样,该函数被find是因为C编译器与C库链接。

请注意,Chris Young对C99和“implicit int”的评论是正确的,但是关于“可变参数函数必须有一个范围原型”的规则适用于C89和C99。 大多数编译器在默认情况下不能以严格的C99兼容模式工作,因为编译的代码太多,不能编译。

Chris Young评论道:

澄清,我的评论是在C99删除隐式声明。 通过说“implicit int”,我认为你指的是C89允许声明的特性,如foo(void); 意思是int foo(void);一些C99也被删除了。

克里斯当然是对的。 从C99标准中删除了两个“隐含声明”的特征。 标准的前言列出了这些标准:

  • 删除隐式int
  • 去除隐式函数声明

我没有足够清楚地思考(因此也没有写)。 尽pipe如此,C89和C99都需要一个原型来处理需要可变数量参数的函数。

为了显示:

 extern int pqr(); int main(void) { int i = pqr(1, 3); return i; } 

没有第一行,这是一个正确的C89片段,它带有函数pqr()的隐式声明,作为返回整数(带有未指定参数)的函数。 如果第一行被extern pqr();所取代extern pqr(); ,那么这是一个正确的C89碎片,并且显式声明了pqr()作为返回一个整数(带有未指定参数)的函数,但返回types是“implicit int ”。 正如所写,该函数是显式声明的,并有一个明确的int返回types – 但它仍然有未指定的参数。 我相信这是有效的C99 – 虽然不是完全可取的。 当然,GCC(3.4.4)接受它的选项是“ -std=c99 -pedantic ”。理想情况下,函数声明应该包含完整的原型(如果pqr()是用省略号定义的,则需要原型理论上 !)

您最初标记了这个C ++,但它似乎是一个C程序。 如果没有原型(例如由于#include <stdio.h>的缺失),C将自动为函数提供隐式声明。 隐含的声明是:

 int printf(); 

这意味着printf是一个函数,返回一个int并可以接受任意数量的参数。 这个原型恰好适合你的电话。 你应该#include <stdio.h>

最后,我要补充一点,目前的C标准(ISO / IEC 9899:1999或俗称“C99”)不允许隐式声明,而且这个程序不符合。 隐式声明已被删除。 我相信你的编译器不支持C99。 C ++也需要正确的原型,不要做隐式声明。

printf()位于标准的C库中,链接器总是将标准库链接到你的可执行文件,所以任何标准函数都会被find,并且不会有链接问题。

如果未包含适当的头文件,将导致使用未经原型化的可能导致问题的函数,因为C编译器假定没有原型的函数将返回int并带有可变数目的参数。 所以总是包括头 – 这是你的安全围栏。