【问题标题】:What exactly is the use of #include<stdio.h> in the traditional "Hello World" program?#include<stdio.h> 在传统的“Hello World”程序中到底有什么用?
【发布时间】:2015-07-27 19:39:59
【问题描述】:

很久以前我就被介绍过 C 编程。最近我在复习我的 C 技能并停留在一个点 - 非常基本的 hello world 程序。我想知道下面代码中#include&lt;stdio.h&gt; 行的用途到底是什么。

/* Hello World Program */

#include<stdio.h>

main()
{
 printf("Hello World");
}

我读到somewhere,当预处理器遇到#include&lt;stdio.h&gt;时,它会将stdio.h头文件的内容添加到源程序中。

另一个article

它会查找 stdio.h 文件并有效地将其复制粘贴到 #include 语句的位置。该文件包含 printf()、scanf()、...等函数的所谓函数原型,以便编译器知道它们的参数和返回值是什么。

所以我只是在玩这个简单的 hello world 程序。我创建了两个版本的代码:-

  1. hello1.c(同上面的代码)
  2. hello2.c(不包括#include&lt;stdio.h&gt;这一行)

我为上述程序创建了目标文件和可执行文件。我观察到 hello1.ohello2.o 的大小是相同的。同样,可执行文件 hello1hello2 的大小也是相同的。

现在我怀疑如果我前面提到的文章是正确的,为什么两个目标文件的大小是一样的?在程序 hello1.c 中,#include&lt;stdio.h&gt; 应替换为函数声明,这将导致目标文件的文件大小与不包括的文件大小不同头文件 (hello2.o)。

我又搜索了一会儿,发现另一个article,上面写着,

头文件只是告诉编译器外部函数和变量是什么类型,定义宏、类型等。没有任何东西被复制。在源文件中引用的任何函数和变量(称为外部符号)都将在链接器阶段被链接。


请哪位高人指点一下哪篇文章是正确的,哪篇是错误的。

非常感谢您的帮助。在此先感谢

【问题讨论】:

  • stdio.h 这样的头文件(通常)不包含实际的函数......它们包含原型,这是对如何与函数交互的描述(它需要什么样的参数,它返回什么样的值等)。包含头文件不会向您的可执行文件/目标文件添加更多代码,它只是确保生成的代码以正确的方式调用库函数(如printf()),并帮助编译器发现代码中的错误。
  • 函数声明在生成的目标代码中不占用空间;它们仅在翻译阶段使用,以确保函数 调用 与函数 定义 匹配(正确的返回类型、正确的参数数量和类型)。
  • 您说您使用该代码创建了一个可执行文件减去 #include ,但肯定不会编译吗?它会抱怨 printf 没有被声明。
  • @SamRedway: printf 返回int,因此如果他使用的是 C89 编译器,则不需要显式声明。请注意,这在 C99 和更高版本的编译器下是编译时错误。
  • function 'prototypes' NOT 函数声明,不增加程序大小,它们是编译器关于函数参数和返回类型的指示。 stdio.h 文件充满了原型和#defines 和#ifdef 类型的语句和结构定义。这些都不会增加程序的大小。要么您使用的是旧编译器,它假定参数和返回类型是 int - 要么 - 您有一个较新的编译器并且没有启用警告(对于 gcc,至少使用:'-Wall -Wextra -pedantic')跨度>

标签: c include header-files


【解决方案1】:

将C程序翻译成二进制目标代码的过程分两步完成:

1) 预处理。这是解释所有以初始# 表示的指令的地方。 #include 就是其中之一。它正在将头文件复制到中间文件(或仅复制到内存)以进行进一步处理。

2) 编译。这是上一步的中间结果,实际上是被翻译成机器码的。

创建可执行文件的时候还有第三步:

3) 链接。它在生成的目标代码中查找引用但未实现的函数,然后在其他目标文件(如果有)或链接库中查找相应的实现。

查看最终代码时,声明(在标头中)不会影响大小,因为编译器需要它们只是“知道”有这样一个在别处调用函数,并且应该使用特定的参数调用来调用它,这样它才能以正确的方式生成调用代码。如果您在没有首先声明的情况下使用函数(当您不包括stdio.h 时会发生这种情况),编译器会“猜测”签名并给您警告“printf 的隐式声明”或类似的.但最终,它与库中正确的 printf 实现链接,因此最终代码实际上与 stdio.h 相同。

【讨论】:

    【解决方案2】:

    两者都是正确的,这取决于您的观点。预处理器在#include 上所做的是在传递给编译器之前包含(字面意思)引用文件的内容。您磁盘上的文件当然不会被修改。

    关于目标文件的大小:C 头文件通常不包含任何代码,仅包含声明。如果标头包含代码,则目标文件的大小会增加。但这不是正常使用。对于库,头文件包含 函数原型 的声明(谷歌以了解它们为什么重要)和可选的外部变量声明以及类型定义预处理器宏和定义,它们可能有助于(甚至是必要的)使用库的 API。

    除此之外:尝试在不启用所有编译器警告的#include &lt;stdio.h&gt; 的情况下编译您的hello 程序(例如,使用gccgcc -Wall -Wextra)——您将收到关于 的警告>printf() 的隐式函数声明。这是因为printf() 的原型是在stdio.h 中声明的。

    并添加一个警告:即使您选择忽略编译器警告,隐式声明一个函数也假定它返回int(出于历史原因)。 printf() 这样做,所以在这种情况下你会没事的。其他函数返回不同的东西,您将遇到运行时崩溃。最好启用所有编译器警告,如果您遇到 隐式声明 警告,请确保您 #include 标头声明您要使用的函数。

    【讨论】:

    • 感谢您宝贵的时间和建议。我想我需要更多地研究对象和可执行文件的标头、数据和其他部分。
    【解决方案3】:

    根据 C11 (N1570) §7.21.1/p1 输入/输出&lt;stdio.h&gt;(强调我的):

    标头&lt;stdio.h&gt;定义了几个宏,声明三个 用于执行输入和输出的类型和许多函数。

    宏和类型定义以及函数声明不会增加目标代码的大小,除非它们在您的代码中实际使用

    例如,如果你定义了一个struct 类型,那么这还不够,你需要创建它的一个实例。以下代码:

    typedef struct car {
        int numberOfWheels; 
    } Car;
    
    int main(void)
    {
        return 0;
    }
    

    将生成与 for 相同的程序集:

    int main(void)
    {
        return 0;
    }
    

    请注意,由于 C99 标准,不提供任何函数声明是无效,该函数在单个翻译单元中调用。在 C89 中,编译器会假设 隐式函数声明,其中:

    • 返回类型为int
    • 实际参数受制于默认参数提升

    【讨论】:

      【解决方案4】:

      让我们先看看实际的language definition

      5.1.1.2 翻译阶段

      1 翻译的语法规则之间的优先级由以下指定 6)

      1. 物理源文件多字节字符被映射,在实现定义 方式,到源字符集(引入换行符 行尾指示符)(如有必要)。三字母序列被替换为 对应的单字符内部表示。
      2. 反斜杠字符 (\) 的每个实例都紧跟一个换行符 字符被删除,拼接物理源行以形成逻辑源行。 只有任何物理源行上的最后一个反斜杠才有资格成为一部分 这样的拼接。非空源文件应以换行符结尾, 在任何此类之前不应紧跟反斜杠字符 发生拼接。
      3. 源文件被分解为预处理标记7)和序列 空白字符(包括 cmets)。源文件不应以 部分预处理标记或部分注释。每条评论都替换为 一个空格字符。保留换行符。是否每个非空 除换行符以外的空白字符序列被保留或替换为 一个空格字符是实现定义的。
      4. 预处理指令被执行,宏调用被扩展,并且 _Pragma 一元运算符表达式被执行。如果一个字符序列 匹配通用字符的语法名称由令牌产生 连接(6.10.3.3),行为未定义。 一个#include预处理 指令使命名的头文件或源文件从阶段 1 开始处理 通过第 4 阶段,递归。 然后删除所有预处理指令。
      5. 每个源字符集成员和字符常量中的转义序列和 字符串字面量被转换为执行字符的对应成员 放;如果没有对应的成员,则转换为实现定义 非空(宽)字符的成员。8)
      6. 连接相邻的字符串文字标记。
      7. 分隔标记的空白字符不再重要。每个 预处理令牌转换为令牌。结果令牌是 句法和语义上的分析和翻译作为一个翻译单元。
      8. 已解析所有外部对象和函数引用。库组件是 链接以满足对未定义的函数和对象的外部引用 当前翻译。所有此类翻译器输出都收集到程序映像中 其中包含在其执行环境中执行所需的信息。

      6) 实现应该表现得好像这些单独的阶段发生了一样,即使许多阶段通常是折叠的 一起实践。源文件、翻译单元和翻译的翻译单元不需要 必须存储为文件,也不需要这些实体之间存在任何一一对应关系 和任何外部代表。描述只是概念性的,并没有具体说明 具体实现。

      7) 如 6.4 所述,将源文件的字符划分为预处理标记的过程是 上下文相关。例如,请参阅 #include 预处理指令中对 &lt; 的处理。

      8) 实现不需要将所有不对应的源字符转换为相同的执行 特点。

      ...
      6.10.2 源文件包含

      约束

      1 #include 指令应标识可由 实施。

      语义

      2 形式为

      # include &lt;<em>h-char-sequence</em>&gt; <em>new-line</em>

      的预处理指令 在一系列实现定义的位置中搜索由唯一标识的标头 &lt;&gt; 分隔符之间的指定序列,并且 导致替换 由标头的全部内容指示。如何指定地点或标题 标识是实现定义的。

      添加了重点。这意味着预处理器将获取源文件

      #include<stdio.h>
      
      main()
      {
       printf("Hello World");
      }
      

      然后生成文本

      /* preprocessed contents of stdio.h here */
      
      main()
      {
        printf("Hello World");
      }
      

      直接提供给编译器。这是我系统上的一个示例(SLES 10,gcc 4.1.2):

      /* hello.c */
      #include <stdio.h>
      
      int main(void)
      {
        printf("Hello, stupid\n");
        return 0;
      }
      

      预处理器输出(gcc -E),稍微重新格式化,准备滚动一会儿:

      # 1 "hello.c"
      # 1 "<built-in>"
      # 1 "<command line>"
      # 1 "hello.c"
      # 1 "/usr/include/stdio.h" 1 3 4
      # 28 "/usr/include/stdio.h" 3 4
      # 1 "/usr/include/features.h" 1 3 4
      # 323 "/usr/include/features.h" 3 4
      # 1 "/usr/include/sys/cdefs.h" 1 3 4
      # 313 "/usr/include/sys/cdefs.h" 3 4
      # 1 "/usr/include/bits/wordsize.h" 1 3 4
      # 314 "/usr/include/sys/cdefs.h" 2 3 4
      # 324 "/usr/include/features.h" 2 3 4
      # 346 "/usr/include/features.h" 3 4
      # 1 "/usr/include/gnu/stubs.h" 1 3 4
      # 1 "/usr/include/bits/wordsize.h" 1 3 4
      # 5 "/usr/include/gnu/stubs.h" 2 3 4
      # 1 "/usr/include/gnu/stubs-64.h" 1 3 4
      # 10 "/usr/include/gnu/stubs.h" 2 3 4
      # 347 "/usr/include/features.h" 2 3 4
      # 29 "/usr/include/stdio.h" 2 3 4
      # 1 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 1 3 4
      # 214 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 3 4
      typedef long unsigned int size_t;
      # 35 "/usr/include/stdio.h" 2 3 4
      # 1 "/usr/include/bits/types.h" 1 3 4
      # 28 "/usr/include/bits/types.h" 3 4
      # 1 "/usr/include/bits/wordsize.h" 1 3 4
      # 29 "/usr/include/bits/types.h" 2 3 4
      # 1 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 1 3 4
      # 32 "/usr/include/bits/types.h" 2 3 4
      
      typedef unsigned char __u_char;
      typedef unsigned short int __u_short;
      typedef unsigned int __u_int;
      typedef unsigned long int __u_long;
      typedef signed char __int8_t;
      typedef unsigned char __uint8_t;
      typedef signed short int __int16_t;
      typedef unsigned short int __uint16_t;
      typedef signed int __int32_t;
      typedef unsigned int __uint32_t;
      typedef signed long int __int64_t;
      typedef unsigned long int __uint64_t;
      typedef long int __quad_t;
      typedef unsigned long int __u_quad_t;
      
      # 134 "/usr/include/bits/types.h" 3 4
      # 1 "/usr/include/bits/typesizes.h" 1 3 4
      # 135 "/usr/include/bits/types.h" 2 3 4
      
      typedef unsigned long int __dev_t;
      typedef unsigned int __uid_t;
      typedef unsigned int __gid_t;
      typedef unsigned long int __ino_t;
      typedef unsigned long int __ino64_t;
      typedef unsigned int __mode_t;
      typedef unsigned long int __nlink_t;
      typedef long int __off_t;
      typedef long int __off64_t;
      typedef int __pid_t;
      typedef struct { int __val[2]; } __fsid_t;
      typedef long int __clock_t;
      typedef unsigned long int __rlim_t;
      typedef unsigned long int __rlim64_t;
      typedef unsigned int __id_t;
      typedef long int __time_t;
      typedef unsigned int __useconds_t;
      typedef long int __suseconds_t;
      typedef int __daddr_t;
      typedef long int __swblk_t;
      typedef int __key_t;
      typedef int __clockid_t;
      typedef void * __timer_t;
      typedef long int __blksize_t;
      typedef long int __blkcnt_t;
      typedef long int __blkcnt64_t;
      typedef unsigned long int __fsblkcnt_t;
      typedef unsigned long int __fsblkcnt64_t;
      typedef unsigned long int __fsfilcnt_t;
      typedef unsigned long int __fsfilcnt64_t;
      typedef long int __ssize_t;
      typedef __off64_t __loff_t;
      typedef __quad_t *__qaddr_t;
      typedef char *__caddr_t;
      typedef long int __intptr_t;
      typedef unsigned int __socklen_t;
      
      # 37 "/usr/include/stdio.h" 2 3 4
      typedef struct _IO_FILE FILE;
      
      # 62 "/usr/include/stdio.h" 3 4
      
      typedef struct _IO_FILE __FILE;
      
      # 72 "/usr/include/stdio.h" 3 4
      # 1 "/usr/include/libio.h" 1 3 4
      # 32 "/usr/include/libio.h" 3 4
      # 1 "/usr/include/_G_config.h" 1 3 4
      # 14 "/usr/include/_G_config.h" 3 4
      # 1 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 1 3 4
      # 326 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 3 4
      
      typedef int wchar_t;
      
      # 355 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 3 4
      
      typedef unsigned int wint_t;
      
      # 15 "/usr/include/_G_config.h" 2 3 4
      # 24 "/usr/include/_G_config.h" 3 4
      # 1 "/usr/include/wchar.h" 1 3 4
      # 48 "/usr/include/wchar.h" 3 4
      # 1 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 1 3 4
      # 49 "/usr/include/wchar.h" 2 3 4
      # 1 "/usr/include/bits/wchar.h" 1 3 4
      # 51 "/usr/include/wchar.h" 2 3 4
      # 76 "/usr/include/wchar.h" 3 4
      
      typedef struct
      {
        int __count;
        union
        {
          wint_t __wch;
          char __wchb[4];
        } __value;
      } __mbstate_t;
      
      # 25 "/usr/include/_G_config.h" 2 3 4
      
      typedef struct
      {
        __off_t __pos;
        __mbstate_t __state;
      } _G_fpos_t;
      
      typedef struct
      {
        __off64_t __pos;
        __mbstate_t __state;
      } _G_fpos64_t;
      
      # 44 "/usr/include/_G_config.h" 3 4
      # 1 "/usr/include/gconv.h" 1 3 4
      # 28 "/usr/include/gconv.h" 3 4
      # 1 "/usr/include/wchar.h" 1 3 4
      # 48 "/usr/include/wchar.h" 3 4
      # 1 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 1 3 4
      # 49 "/usr/include/wchar.h" 2 3 4
      # 29 "/usr/include/gconv.h" 2 3 4
      # 1 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stddef.h" 1 3 4
      # 32 "/usr/include/gconv.h" 2 3 4
      
      enum
      {
        __GCONV_OK = 0,
        __GCONV_NOCONV,
        __GCONV_NODB,
        __GCONV_NOMEM,
        __GCONV_EMPTY_INPUT,
        __GCONV_FULL_OUTPUT,
        __GCONV_ILLEGAL_INPUT,
        __GCONV_INCOMPLETE_INPUT,
        __GCONV_ILLEGAL_DESCRIPTOR,
        __GCONV_INTERNAL_ERROR
      };
      
      enum
      {
        __GCONV_IS_LAST = 0x0001,
        __GCONV_IGNORE_ERRORS = 0x0002
      };
      
      struct __gconv_step;
      struct __gconv_step_data;
      struct __gconv_loaded_object;
      struct __gconv_trans_data;
      typedef int (*__gconv_fct) (struct __gconv_step *, struct __gconv_step_data *,
             __const unsigned char **, __const unsigned char *,
             unsigned char **, size_t *, int, int);
      typedef wint_t (*__gconv_btowc_fct) (struct __gconv_step *, unsigned char);
      typedef int (*__gconv_init_fct) (struct __gconv_step *);
      typedef void (*__gconv_end_fct) (struct __gconv_step *);
      typedef int (*__gconv_trans_fct) (struct __gconv_step *,
            struct __gconv_step_data *, void *,
            __const unsigned char *,
            __const unsigned char **,
            __const unsigned char *, unsigned char **,
            size_t *);
      typedef int (*__gconv_trans_context_fct) (void *, __const unsigned char *,
             __const unsigned char *,
             unsigned char *, unsigned char *);
      typedef int (*__gconv_trans_query_fct) (__const char *, __const char ***,
           size_t *);
      typedef int (*__gconv_trans_init_fct) (void **, const char *);
      typedef void (*__gconv_trans_end_fct) (void *);
      struct __gconv_trans_data
      {
        __gconv_trans_fct __trans_fct;
        __gconv_trans_context_fct __trans_context_fct;
        __gconv_trans_end_fct __trans_end_fct;
        void *__data;
        struct __gconv_trans_data *__next;
      };
      
      struct __gconv_step
      {
        struct __gconv_loaded_object *__shlib_handle;
        __const char *__modname;
        int __counter;
        char *__from_name;
        char *__to_name;
        __gconv_fct __fct;
        __gconv_btowc_fct __btowc_fct;
        __gconv_init_fct __init_fct;
        __gconv_end_fct __end_fct;
        int __min_needed_from;
        int __max_needed_from;
        int __min_needed_to;
        int __max_needed_to;
        int __stateful;
        void *__data;
      };
      
      struct __gconv_step_data
      {
        unsigned char *__outbuf;
        unsigned char *__outbufend;
        int __flags;
        int __invocation_counter;
        int __internal_use;
        __mbstate_t *__statep;
        __mbstate_t __state;
        struct __gconv_trans_data *__trans;
      };
      
      typedef struct __gconv_info
      {
        size_t __nsteps;
        struct __gconv_step *__steps;
        __extension__ struct __gconv_step_data __data [];
      } *__gconv_t;
      
      # 45 "/usr/include/_G_config.h" 2 3 4
      
      typedef union
      {
        struct __gconv_info __cd;
        struct
        {
          struct __gconv_info __cd;
          struct __gconv_step_data __data;
        } __combined;
      } _G_iconv_t;
      
      typedef int _G_int16_t __attribute__ ((__mode__ (__HI__)));
      typedef int _G_int32_t __attribute__ ((__mode__ (__SI__)));
      typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__)));
      typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__)));
      
      # 33 "/usr/include/libio.h" 2 3 4
      # 53 "/usr/include/libio.h" 3 4
      # 1 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stdarg.h" 1 3 4
      # 43 "/usr/lib64/gcc/x86_64-suse-linux/4.1.2/include/stdarg.h" 3 4
      typedef __builtin_va_list __gnuc_va_list;
      # 54 "/usr/include/libio.h" 2 3 4
      # 167 "/usr/include/libio.h" 3 4
      
      struct _IO_jump_t; struct _IO_FILE;
      
      # 177 "/usr/include/libio.h" 3 4
      
      typedef void _IO_lock_t;
      struct _IO_marker {
        struct _IO_marker *_next;
        struct _IO_FILE *_sbuf;
        int _pos;
      
      # 200 "/usr/include/libio.h" 3 4
      
      };
      
      
      enum __codecvt_result
      {
        __codecvt_ok,
        __codecvt_partial,
        __codecvt_error,
        __codecvt_noconv
      };
      
      # 268 "/usr/include/libio.h" 3 4
      
      struct _IO_FILE {
        int _flags;
        char* _IO_read_ptr;
        char* _IO_read_end;
        char* _IO_read_base;
        char* _IO_write_base;
        char* _IO_write_ptr;
        char* _IO_write_end;
        char* _IO_buf_base;
        char* _IO_buf_end;
        char *_IO_save_base;
        char *_IO_backup_base;
        char *_IO_save_end;
        struct _IO_marker *_markers;
        struct _IO_FILE *_chain;
        int _fileno;
        int _flags2;
        __off_t _old_offset;
        unsigned short _cur_column;
        signed char _vtable_offset;
        char _shortbuf[1];
        _IO_lock_t *_lock;
      
      # 316 "/usr/include/libio.h" 3 4
      
        __off64_t _offset;
      
      # 325 "/usr/include/libio.h" 3 4
        void *__pad1;
        void *__pad2;
        void *__pad3;
        void *__pad4;
        size_t __pad5;
        int _mode;
        char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
      };
      
      typedef struct _IO_FILE _IO_FILE;
      struct _IO_FILE_plus;
      extern struct _IO_FILE_plus _IO_2_1_stdin_;
      extern struct _IO_FILE_plus _IO_2_1_stdout_;
      extern struct _IO_FILE_plus _IO_2_1_stderr_;
      # 361 "/usr/include/libio.h" 3 4
      typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes);
      typedef __ssize_t __io_write_fn (void *__cookie, __const char *__buf,
           size_t __n);
      typedef int __io_seek_fn (void *__cookie, __off64_t *__pos, int __w);
      typedef int __io_close_fn (void *__cookie);
      # 413 "/usr/include/libio.h" 3 4
      extern int __underflow (_IO_FILE *) __attribute__ ((__nothrow__));
      extern int __uflow (_IO_FILE *) __attribute__ ((__nothrow__));
      extern int __overflow (_IO_FILE *, int) __attribute__ ((__nothrow__));
      extern wint_t __wunderflow (_IO_FILE *) __attribute__ ((__nothrow__));
      extern wint_t __wuflow (_IO_FILE *) __attribute__ ((__nothrow__));
      extern wint_t __woverflow (_IO_FILE *, wint_t) __attribute__ ((__nothrow__));
      # 451 "/usr/include/libio.h" 3 4
      extern int _IO_getc (_IO_FILE *__fp) __attribute__ ((__nothrow__));
      extern int _IO_putc (int __c, _IO_FILE *__fp) __attribute__ ((__nothrow__));
      extern int _IO_feof (_IO_FILE *__fp) __attribute__ ((__nothrow__));
      extern int _IO_ferror (_IO_FILE *__fp) __attribute__ ((__nothrow__));
      extern int _IO_peekc_locked (_IO_FILE *__fp) __attribute__ ((__nothrow__));
      extern void _IO_flockfile (_IO_FILE *) __attribute__ ((__nothrow__));
      extern void _IO_funlockfile (_IO_FILE *) __attribute__ ((__nothrow__));
      extern int _IO_ftrylockfile (_IO_FILE *) __attribute__ ((__nothrow__));
      # 481 "/usr/include/libio.h" 3 4
      extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict,
         __gnuc_va_list, int *__restrict);
      extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,
          __gnuc_va_list);
      extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t) __attribute__ ((__nothrow__));
      extern size_t _IO_sgetn (_IO_FILE *, void *, size_t) __attribute__ ((__nothrow__));
      extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t, int, int) __attribute__ ((__nothrow__));
      extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t, int) __attribute__ ((__nothrow__));
      extern void _IO_free_backup_area (_IO_FILE *) __attribute__ ((__nothrow__));
      # 73 "/usr/include/stdio.h" 2 3 4
      # 86 "/usr/include/stdio.h" 3 4
      typedef _G_fpos_t fpos_t;
      # 138 "/usr/include/stdio.h" 3 4
      # 1 "/usr/include/bits/stdio_lim.h" 1 3 4
      # 139 "/usr/include/stdio.h" 2 3 4
      extern struct _IO_FILE *stdin;
      extern struct _IO_FILE *stdout;
      extern struct _IO_FILE *stderr;
      extern int remove (__const char *__filename) __attribute__ ((__nothrow__));
      extern int rename (__const char *__old, __const char *__new) __attribute__ ((__nothrow__));
      extern FILE *tmpfile (void);
      # 185 "/usr/include/stdio.h" 3 4
      extern char *tmpnam (char *__s) __attribute__ ((__nothrow__));
      extern char *tmpnam_r (char *__s) __attribute__ ((__nothrow__));
      # 203 "/usr/include/stdio.h" 3 4
      extern char *tempnam (__const char *__dir, __const char *__pfx)
           __attribute__ ((__nothrow__)) __attribute__ ((__malloc__));
      extern int fclose (FILE *__stream);
      extern int fflush (FILE *__stream);
      # 228 "/usr/include/stdio.h" 3 4
      extern int fflush_unlocked (FILE *__stream);
      # 228 "/usr/include/stdio.h" 3 4
      extern int fflush_unlocked (FILE *__stream);
      # 242 "/usr/include/stdio.h" 3 4
      extern FILE *fopen (__const char *__restrict __filename,
            __const char *__restrict __modes);
      extern FILE *freopen (__const char *__restrict __filename,
              __const char *__restrict __modes,
              FILE *__restrict __stream);
      # 269 "/usr/include/stdio.h" 3 4
      # 280 "/usr/include/stdio.h" 3 4
      extern FILE *fdopen (int __fd, __const char *__modes) __attribute__ ((__nothrow__));
      # 306 "/usr/include/stdio.h" 3 4
      extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __attribute__ ((__nothrow__));
      extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf,
            int __modes, size_t __n) __attribute__ ((__nothrow__));
      extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf,
               size_t __size) __attribute__ ((__nothrow__));
      extern void setlinebuf (FILE *__stream) __attribute__ ((__nothrow__));
      extern int fprintf (FILE *__restrict __stream,
            __const char *__restrict __format, ...);
      extern int printf (__const char *__restrict __format, ...);
      extern int sprintf (char *__restrict __s,
            __const char *__restrict __format, ...) __attribute__ ((__nothrow__));
      extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format,
             __gnuc_va_list __arg);
      extern int vprintf (__const char *__restrict __format, __gnuc_va_list __arg);
      extern int vsprintf (char *__restrict __s, __const char *__restrict __format,
             __gnuc_va_list __arg) __attribute__ ((__nothrow__));
      extern int snprintf (char *__restrict __s, size_t __maxlen,
             __const char *__restrict __format, ...)
           __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 4)));
      extern int vsnprintf (char *__restrict __s, size_t __maxlen,
              __const char *__restrict __format, __gnuc_va_list __arg)
           __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 0)));
      # 400 "/usr/include/stdio.h" 3 4
      extern int fscanf (FILE *__restrict __stream,
           __const char *__restrict __format, ...) ;
      extern int scanf (__const char *__restrict __format, ...) ;
      extern int sscanf (__const char *__restrict __s,
           __const char *__restrict __format, ...) __attribute__ ((__nothrow__));
      # 442 "/usr/include/stdio.h" 3 4
      extern int fgetc (FILE *__stream);
      extern int getc (FILE *__stream);
      extern int getchar (void);
      # 466 "/usr/include/stdio.h" 3 4
      extern int getc_unlocked (FILE *__stream);
      extern int getchar_unlocked (void);
      # 477 "/usr/include/stdio.h" 3 4
      extern int fgetc_unlocked (FILE *__stream);
      extern int fputc (int __c, FILE *__stream);
      extern int putc (int __c, FILE *__stream);
      extern int putchar (int __c);
      # 510 "/usr/include/stdio.h" 3 4
      extern int fputc_unlocked (int __c, FILE *__stream);
      extern int putc_unlocked (int __c, FILE *__stream);
      extern int putchar_unlocked (int __c);
      extern int getw (FILE *__stream);
      extern int putw (int __w, FILE *__stream);
      extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
           ;
      extern char *gets (char *__s) ;
      # 591 "/usr/include/stdio.h" 3 4
      extern int fputs (__const char *__restrict __s, FILE *__restrict __stream);
      extern int puts (__const char *__s);
      extern int ungetc (int __c, FILE *__stream);
      extern size_t fread (void *__restrict __ptr, size_t __size,
             size_t __n, FILE *__restrict __stream) ;
      extern size_t fwrite (__const void *__restrict __ptr, size_t __size,
              size_t __n, FILE *__restrict __s) ;
      # 644 "/usr/include/stdio.h" 3 4
      extern size_t fread_unlocked (void *__restrict __ptr, size_t __size,
               size_t __n, FILE *__restrict __stream) ;
      extern size_t fwrite_unlocked (__const void *__restrict __ptr, size_t __size,
                size_t __n, FILE *__restrict __stream) ;
      extern int fseek (FILE *__stream, long int __off, int __whence);
      extern long int ftell (FILE *__stream) ;
      extern void rewind (FILE *__stream);
      # 680 "/usr/include/stdio.h" 3 4
      extern int fseeko (FILE *__stream, __off_t __off, int __whence);
      extern __off_t ftello (FILE *__stream) ;
      # 699 "/usr/include/stdio.h" 3 4
      extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos);
      extern int fsetpos (FILE *__stream, __const fpos_t *__pos);
      # 722 "/usr/include/stdio.h" 3 4
      # 731 "/usr/include/stdio.h" 3 4
      extern void clearerr (FILE *__stream) __attribute__ ((__nothrow__));
      extern int feof (FILE *__stream) __attribute__ ((__nothrow__)) ;
      extern int ferror (FILE *__stream) __attribute__ ((__nothrow__)) ;
      extern void clearerr_unlocked (FILE *__stream) __attribute__ ((__nothrow__));
      extern int feof_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
      extern int ferror_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
      extern void perror (__const char *__s);
      # 1 "/usr/include/bits/sys_errlist.h" 1 3 4
      # 27 "/usr/include/bits/sys_errlist.h" 3 4
      extern int sys_nerr;
      extern __const char *__const sys_errlist[];
      # 761 "/usr/include/stdio.h" 2 3 4
      extern int fileno (FILE *__stream) __attribute__ ((__nothrow__)) ;
      extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__)) ;
      # 780 "/usr/include/stdio.h" 3 4
      extern FILE *popen (__const char *__command, __const char *__modes) ;
      extern int pclose (FILE *__stream);
      extern char *ctermid (char *__s) __attribute__ ((__nothrow__));
      # 820 "/usr/include/stdio.h" 3 4
      extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__));
      extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__)) ;
      extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__));
      # 850 "/usr/include/stdio.h" 3 4
      # 2 "hello.c" 2
      int main(void)
      {
        printf("Hello, stupid\n");
        return 0;
      }
      

      然后将预处理器阶段的输出馈送到解析器(阶段 7);预处理器输出是否在输入解析器之前保存到临时文件中取决于实现。

      注意stdio.h包含其他头文件(features.htypes.hlibio.h等),可能依次包含其他头文件。结果输出是这些头文件中指定的所有类型定义和外部(非定义)函数和对象声明的污泥。

      没有污泥最终出现在实际的目标文件中;对象文件中唯一占用空间的是函数和对象定义,例如您的 main 函数体、字符串字面量和 printf 的实现(以及任何其他操作系统需要对象和机器代码才能使其成为可运行的程序)。

      鉴于简单的main() 编译没有问题,您显然使用的是C89 或更早版本的编译器,它允许隐式int 声明; IOW,如果编译器看到一个没有相应声明的函数调用,或者一个没有类型说明符的函数定义,它假定函数返回int。由于printf 返回int,您的没有stdio.h 的版本编译和链接没有问题。如果您使用的是 C99 或更高版本的编译器,或者调用了 not 返回 int 的库函数,您将在编译时得到诊断。

      【讨论】:

        猜你喜欢
        • 2013-10-05
        • 1970-01-01
        • 2019-01-17
        • 2012-11-20
        • 2015-03-19
        • 2012-11-29
        • 2011-09-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多