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

时间:2008-12-03 10:57:50

标签: c include printf declaration

会话记录:

>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

3 个答案:

答案 0 :(得分:37)

您最初标记了此C ++,但它似乎是一个C程序。如果范围内没有原型(例如由于省略#include&lt; stdio.h&gt;),C将自动为函数提供隐式声明。隐含的声明是:

int printf();

这意味着printf是一个返回int的函数,可以接受任意数量的参数。这个原型恰好适合您的通话。你应该#include&lt; stdio.h&gt;

最后,我应该补充一点,当前的C标准(ISO / IEC 9899:1999或俗称“C99”)确实允许隐式声明,并且该程序不符合。删除了隐式声明。我相信你的编译器不支持C99。 C ++还需要正确的原型,不进行隐式声明。

答案 1 :(得分:31)

在严格遵从模式(意思是“在理论上”)中,当您调用一个函数时调用未定义的行为(这是不好的),该函数接受可变数量的参数而没有函数的原型声明。这意味着允许编译器对使用printf()的程序执行任何操作,而不使用#include <stdio.h>的原型或等效声明。 “任何它喜欢的东西”包括正确地作为选项之一;这似乎是你的例子选择的选项。

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

正如qrdl所指出的,找到了该函数,因为C编译器与C库链接。

请注意,Chris Young关于C99和'implicit int'的评论是准确的,但关于'变量参数函数必须在范围内具有原型'的规则适用于C89和C99。默认情况下,大多数编译器不能在严格的C99兼容模式下工作,因为有太多代码无法像这样编译。

Chris Young评论道:

  

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

当然,克里斯是正确的。从C99标准中删除了两个“隐式声明”功能。标准的前言将它们列为:

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

我没有想清楚(因而也没有写作)。尽管如此,C89和C99都需要一个范围原型,用于采用可变数量参数的函数。

举例说明:

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

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

答案 2 :(得分:9)

printf()位于标准C库中,链接器始终将标准库链接到您的可执行文件,因此将找到任何标准函数,并且不存在链接问题。

由于C编译器假定没有原型的函数返回int并且需要可变数量的参数,因此未能在使用非原型化的函数时包含适当的头结果会导致问题。所以总是包括标题 - 这是你的安全围栏。