目录

  • 预编译简介
  • 预编译定义
  • 预编译在整个编译链接过程中的作用
  • 预编译所做的工作
  • 预编译的处理规则
  • #define规则
  • #include规则
  • 条件预编译指令
  • 注释规则
  • 行号和文件名标识规则
  • #pragma指令
  • 参考文献

预编译简介

预编译定义

预编译又称为预处理,是做些代码文本的替换工作。是整个编译过程的最先做的工作。

预编译在整个编译链接过程中的作用

首先我们来看一个简单的编译链接过程:
预编译–>编译–>汇编–>链接
正如定义所言,预编译为整个编译链接最先做的工作。

预编译所做的工作

在c语言中,预编译将.h文件进行文本级的扩展(可理 解为你把头文件中的内容ctrl+v粘贴到.c文件中),与.c 文件一起编译成.i中间文件。
在C++中,预编译将.cpp和.hpp文件编译成.ii中间文件 在linux平台下其编译过程相当于如下命令(-E表示只 进行预编译)

$ gcc -E hello.c -o  hello.i

预编译的处理规则

#define规则

编译器将所有的#define删除,并展开宏定义
例如以下代码

#define A 5
	int a = A;

此代码在预编译结束后就是 int a = 5;

#define除此之外常用的地方就是宏函数了,其比C++中inline函数更加高效:

//字符串转换为小写的函数
#define tolower(c) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#include规则

#include 作用的包含文件,在linux平台下,编译器将会在 /usr/local/include路径下被包含的文件插入到该预编译指令的位置,这个过程是递归进行的。

注:
#include 可以包含任何文件,也就是说,我们甚至可以包含二进制文件
#include “a.o” //语句合法

除了最常用的包含头文件之外,我们还可以用#include玩点小花样,假如说我们有一组数据:

static uint32_t num_table[] = { 
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
    ...};

这样非常的不灵活,我们可以把这组数据定义在number.inc 文件中,之后在原来的地方替换就可以:

C预言java预言混编 c语言预编译的作用_linux

static uint32_t num_table[] = {
#include "number.inc"
};

int main()
{
    cout << num_table[3] << endl;
}
//输出结果:2567524794
条件预编译指令

在预编译要处理所有的条件预编译指令,比如#if#ifdef#else#endif
而其中的#ifndef#define#endif指令便是用来处理刚刚的头文件重复包含问题。
以下是个例子:

#ifndef _HELLO_H_
	#define _HELLO_H_
	int main()
	{
		...
	}
	#endif
注释规则

在预编译阶段要处理(删掉)所有的注释“//”,“/* … */”,并替换为一个空格,说明这里有注释存在

行号和文件名标识规则

预编译阶段会添加行号和文件名标识,以便于编译时编译器所产生调试用的行号信息,以及在产生错误能给你一个行号来提示错误位置

#pragma指令

这个指令是要保留的因为编译器需要使用它们