c/docs/notes/02_c-leap/06_xdx/index.md
2024-10-09 01:45:00 +00:00

4.4 KiB
Raw Blame History

第一章:基本介绍

1.1 回顾 C 语言的编译过程

  • C 语言的编译过程,如下所示:

  • 过程 ① :编写(编辑)源代码,即:编写 C 语言源程序代码,并以文件的形式存储在磁盘中。

Note

源程序需要以 .c 作为扩展名。

  • 过程 ② :编译,即:将 C 语言源程序转换为目标程序(或目标文件)。如果程序没有错误,没有任何提示,就会生成一个扩展名为 .obj.o 的二进制文件。C 语言中的每条可执行语句经过编译之后,最终都会转换为二进制的机器指令。

Note

  • ① 其实,编译阶段包含了预处理编译汇编
  • 预处理是编译过程的第一个阶段。在这个阶段,预处理器处理源代码中的指令(例如:#include#define等),主要任务包括:
    • 头文件包含:将头文件的内容插入到源文件中。例如:#include <stdio.h>会被替换为stdio.h文件的内容。
    • 宏展开:替换宏定义。例如:#define PI 3.14会将代码中的PI替换为3.14
    • 条件编译:根据条件指令(如:#ifdef#ifndef)有选择地编译代码。
    • 删除代码中的注释,但是不会进行语法检查。
    • 预处理完成后,生成一个扩展名为.i的中间文件。
  • 编译是将预处理后的源代码转换为汇编代码的过程。在这个阶段,编译器会检查代码的语法和语义,将其转换为目标机器的汇编语言,生成一个扩展名为.s的汇编文件。
  • 汇编是将汇编代码转换为机器代码(也称为目标代码或目标文件)的过程。在这个阶段,汇编器将汇编指令转换为二进制机器指令,生成一个扩展名为.o.obj的目标文件。
  • 过程 ③ :链接(连接),即:将编译形成的目标文件 *.obj*.o和库函数以及其他目录文件链接,形成一个统一的二进制文件 *.exe

Note

  • 为什么需要链接库文件?
  • 因为我们的 C 程序会使用 C 程序库中的内容,如:<stdio.h> 中的 printf() 函数,这些函数不是程序员自己写的,而是 C 程序库中提供的因此需要链接。其实在链接过程中还会加入启动代码这个启动代码和系统相关Linux 下主要有 crt0.c、crti.c 等,它们设置堆栈后,再调用 main() 函数)负责初始化程序运行时的环境。
  • 过程 ④ :执行,即:有了可执行的 *.exe文件,我们就可以在控制台上执行运行此 *.exe 文件。

Note

如果修改了源代码,还需要重新编译链接,并生成新的 *.exe文件,再执行,方能生效。

1.2 和其他编程语言的对比

  • 在编译和链接之前C 语言需要对源文件进行一些文本方面的操作,如:删除代码中的注释,但是不会进行语法检查、头文件包含、宏展开、条件编译等,这个过程叫做预处理,由预处理程序(预处理器)完成。
  • 较之其他的编程语言Java 、C# 等C/C++ 语言更依赖预处理器,所以在阅读或开发 C/C++ 程序的过程中,可能会接触到大量的预处理指令,如:#include#define 等。

1.3 预处理指令

  • 预处理过程中会执行预处理指令,预处理指令以 #开头,如:#include 等,用于指导预处理器执行不同的任务。

  • 预处理器有如下的特点:

    • ① 预处理指令应该放在代码的开头部分。

    • ② 预处理指令都以 #开头,指令前面可以有空白字符(比如空格或制表符),#和指令的其余部分之间也可以有空格,但是为了兼容老的编译器,一般不留空格。

      // 推荐写法
      #include <stdio.h>
      
      // 不推荐写法
          #include <stdio.h>
      # include <stdio.h>
      
    • ③ 预处理指令都是一行的,除非在行尾使用反斜杠,将其折行。

      #include <std\
      io.h>
      
    • ④ 预处理指令不需要分号作为结束符,指令结束是通过换行符来识别的。

      #include <stdio.h>; 	// 这里有分号会报错
      

第二章:宏定义

第三章:带参数的宏定义

第四章:文件包含

第五章:条件编译