编译的过程——预处理
- 引言
- 预处理
- 包含头文件
- 宏定义指令
- 条件编译
- 编译、链接
引言
C++程序编译的过程:预处理 -> 编译(优化、汇编)-> 链接
编译和链接的内容可以查阅这篇文章(点击查看)
预处理
编译预处理
是指,对我们写的源代码进行预处理,生成临时文件。
预处理指令主要有以下 三种:
- 包含头文件:
#include
- 宏定义:
#define
(定义宏)、#undef
(删除宏) - 条件编译:
#ifdef
、#ifndef
包含头文件
#include
包含头文件有两种方式:
#include <文件名>
:直接从编译器自带的函数库目录中寻找文件。这种情况用于包含编译器自带的头文件
,也叫系统文件
。#include "文件名"
:先从自定义的目录中寻找文件,如果找不到,再从编译器自带的函数库目录中寻找。这种情况用于包含程序员自定义的头文件
。
#include
也包含其它的文件,如:.h
、.cpp
或其它的文件。#include
包含文件的本质是把需要包含的文件的内容复制进来。
C++98标准后的头文件分为C标准库和C++标准库:
- C的标准库:老版本的有.h后缀;新版本没有.h的后缀,增加了字符c的前缀。例如:老版本是
<stdio.h>
,新版本是<cstdio>
,新老版本库中的内容是一样的。在程序中,不指定std命名空间也能使用库中的内容。 - C++的标准库:老版本的有.h后缀;新版本没有.h的后缀。例如:老版本是
<iostream.h>
,新版本是<iostream>
,老版本已弃用,只能用新版本
。在程序中,必须指定
std命名空间
才能使用库中的内容。
注意:用户自定义的头文件还是用.h为后缀。
宏定义指令
- 无参数的宏:
#define 宏名 宏内容
- 有参数的宏:
#define MAX(x,y) ((x)>(y) ? (x) : (y))
编译的时候,编译器把程序中的宏名
用宏内容替换
,是为宏展开(宏替换)
。
宏可以只有宏名,没有宏内容。
在C++中,内联函数可代替有参数的宏,效果更好。
C++中常用的宏:
- 当前源代码文件名:
__FILE__
- 当前源代码函数名:
__FUNCTION__
- 当前源代码行号:
__LINE__
- 编译的日期:
__DATE__
- 编译的时间:
__TIME__
- 编译的时间戳:
__TIMESTAMP__
- 当用C++编译程序时,宏
__cplusplus
就会被定义。
可以自行打印一下宏的内容,如下:
cout << "__FILE__: " << __FILE__ << endl;
cout << "__FUNCTION__: " << __FUNCTION__ << endl;
cout << "__TIMESTAMP__: " << __TIMESTAMP__ << endl;
cout << "__cplusplus: " << __cplusplus << endl;
条件编译
最常用的两种:#ifdef
、#ifndef
#ifdef 宏名
程序段一
#else
程序段二
#endif
含义:如果#ifdef
后面的宏名已存在
,则使用程序段一,否则使用程序段二。
#ifndef 宏名
程序段一
#else
程序段二
#endif
含义:如果#ifndef
后面的宏名不存在
,则使用程序段一,否则使用序段二。
什么是宏名存在?什么是不存在?
如果用#define
定义宏,宏名就存在;没定义宏,宏名就不存在。宏的内容无所谓,只要有名字就行。
ifdef
、ifndef
、else
、 endif
这些是条件编译
语句,与条件判断语句不是一回事。
在C++中,头文件只需要被包含一次就行了。在C/C++中,在使用预编译指令#include
的时候,为了防止头文件被重复包含
,有两种方式。
- 方式1:用
#ifndef
指令。
#ifndef _CAR_
#define _CAR_
//代码内容。
#endif
- 方式2:
#pragma once
指令放在文件的开头
#pargma once
#include <iostream>
using namespace std:
...
#ifndef
方式受C/C++语言标准的支持,不受编译器的任何限制;而#pragma once
方式有些编译器不支持。
#ifndef
可以针对文件中的部分代码;而#pragma once
只能针对整个文件。
#ifndef
更加灵活,兼容性好;#pragma once
操作简单,效率高。
编译、链接
点击查看这篇文章
感谢浏览,一起学习!