预处理指令包括在(由井号前面的程序代码行
#
)。这些行不是程序语句,但是指令的
预处理器。预处理器检查代码之前的代码的实际编译开始,并解决了所有这些指令之前,通过定期报表实际产生的任何代码。
这些
预处理指令只跨越一个单一的代码行延伸。只要一个换行符被发现,预处理指令是结束。别无分号(
;
)在预处理指令结束的预期。预处理程序指令可通过多条线路延长的唯一方法是通过一个反斜杠在该行的末尾换行符前面的(
\
)。
宏定义(#定义,和#undef)
要定义我们可以使用预处理宏
#define
。它的语法是: 当遇到预处理这个指令,它会替换任何发生由代码的其余部分。这可以是一个表达式,语句,块或者干脆什么。预处理器并不了解C ++正确的,它只是替换出现的任何通过。
#define identifier replacement
identifier
replacement
replacement
identifier
replacement
1
2
3
| #define TABLE_SIZE 100
int table1[TABLE_SIZE];
int table2[TABLE_SIZE]; | |
预处理器已经取代后
TABLE_SIZE
,代码变得等同于:
1
2
| int table1[100];
int table2[100]; | |
#define
可以带参数也一起定义函数宏:
| #define getmax(a,b) a>b?a:b | |
这将取代任何发生
getmax
的替换表达式后跟两个参数,而且通过其标识符替换每个参数,正如你所期望的,如果它是一个函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // function macro
#include <iostream>
using namespace std;
#define getmax(a,b) ((a)>(b)?(a):(b))
int main()
{
int x=5, y;
y= getmax(x,2);
cout << y << endl;
cout << getmax(7,x) << endl;
return 0;
} | 五
7 |
|
定义的宏不受块结构。宏一直持续到它与未定义
#undef
预处理指令:
1
2
3
4
5
| #define TABLE_SIZE 100
int table1[TABLE_SIZE];
#undef TABLE_SIZE
#define TABLE_SIZE 200
int table2[TABLE_SIZE]; | |
这将生成代码相同:
1
2
| int table1[100];
int table2[200]; | |
功能宏定义接受两个特殊的运营商(
#
和
##
在更换顺序):
运营商
#
,其次是参数名称,是由一个字符串文字包含传递的参数(好像封闭双引号)替换为:
1
2
| #define str(x) #x
cout << str(test); | |
这将被翻译成:
运营商
##
连接两个参数让他们之间没有空格:
1
2
| #define glue(a,b) a ## b
glue(c,out) << "test"; | |
这也将被翻译成:
由于预处理器替换任何C ++语法检查之前发生,宏定义可以是一个棘手的功能。但是,要小心:代码很大程度上依赖于复杂的宏变得不太可读,因为预期语法是从正常的表达程序员在C ++中不同的期望很多场合。
条件包括(#IFDEF,的#ifndef,#如果,#ENDIF,的#else和#elif)
这些指令允许以包括或者如果某个条件得到满足丢弃的程序的代码的一部分。
#ifdef
允许节目的部分仅当被指定为参数的宏已定义,不论其值是进行编译。例如:
1
2
3
| #ifdef TABLE_SIZE
int table[TABLE_SIZE];
#endif | |
在这种情况下,代码行
int table[TABLE_SIZE];
,如果仅编译
TABLE_SIZE
预先用所定义
#define
的值无关。如果它没有被定义,线将不包括在程序编译。
#ifndef
服务于完全相反:之间的代码
#ifndef
和
#endif
指令如果指定的标识符没有被预先定义的仅编译。例如:
1
2
3
4
| #ifndef TABLE_SIZE
#define TABLE_SIZE 100
#endif
int table[TABLE_SIZE]; | |
在这种情况下,如果在这段代码到达时,在
TABLE_SIZE
宏尚未定义,这将被定义为100的值。如果它已经存在它将保持其先前的值,因为该
#define
指令将不会执行。
的
#if
,
#else
和
#elif
(即“否则如果”)指令用来指定顺序来满足它们包围要编译的代码部分的一些条件。下面的条件
#if
或
#elif
只能计算常数表达式,包括宏表达式。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| #if TABLE_SIZE>200
#undef TABLE_SIZE
#define TABLE_SIZE 200
#elif TABLE_SIZE<50
#undef TABLE_SIZE
#define TABLE_SIZE 50
#else
#undef TABLE_SIZE
#define TABLE_SIZE 100
#endif
int table[TABLE_SIZE]; | |
注意的整个结构如何
#if
,
#elif
以及
#else
链接的指令结尾
#endif
。
的行为
#ifdef
和
#ifndef
还可以通过使用特殊的经营者实现
defined
和
!defined
在任意分别
#if
或
#elif
指令:
1
2
3
4
5
6
7
| #if defined ARRAY_SIZE
#define TABLE_SIZE ARRAY_SIZE
#elif !defined BUFFER_SIZE
#define TABLE_SIZE 128
#else
#define TABLE_SIZE BUFFER_SIZE
#endif | |
线控制(#行)
当我们编译程序并在编译过程会发生一些错误,编译器示出了到该错误发生的文件和一个行号的名称的引用的错误消息,因此它是容易找到码生成的误差。
该
#line
指令允许我们控制代码文件中的两件事,行号和文件名,我们希望,当错误发生时出现。其格式为: 其中是将分配给下一个代码行中的新行号。连续行的行号将被一个从在这一点上增加之一。是,允许重新定义将要示出的文件名的可选参数。例如:
#line number "filename"
number
"filename"
1
2
| #line 20 "assigning variable"
int a?; | |
此代码将产生将显示为错误文件的错误
"assigning variable"
,20行。
错误指令(#ERROR)
该指令中止的时候才发现,生成可以被指定为它的参数编译错误编译过程:
1
2
3
| #ifndef __cplusplus
#error A C++ compiler is required!
#endif | |
这个例子中止如果宏名编译过程
__cplusplus
没有被定义(这宏的名称默认情况下,在所有的C ++编译器定义)。
源文件包含(#包括)
该指令已在本教程的其他部分所用刻苦钻研。当预处理器发现一个
#include
指令它通过指定的头或文件的全部内容来替换它。有使用两种方法
#include
:
1
2
| #include <header>
#include "file" | |
在第一种情况下,一个
标题是尖括号之间指定
<>
。这是用来包括由实现提供标头,诸如构成该标准库(标题
iostream
,
string
...)。无论是头实际上是文件或者以其他形式存在是
实现定义的,但在任何情况下,他们应适当地包括这项指令。
在第二个中使用的语法
#include
使用报价,并包括一个
文件。该
文件中搜索以
实现定义的方式,它一般包括当前路径。在该文件中没有找到的情况下,编译器解释该指令作为一个
标题包含,就好像引号(
""
)由角括号取代(
<>
)。
编译指令(的#pragma)
该指令用于指定不同的选项编译器。这些选项是特定于平台和使用编译器。查阅手册或编译器上,你可以定义可能的参数的详细信息参考
#pragma
。
如果编译器不支持特定的论据
#pragma
,它被忽略-不会生成语法错误。
预定义宏名
下面的宏的名字总是定义(它们都开始并用两个下划线字符,结束
_
):
宏 | 值 |
---|
__LINE__ | 代表在源代码文件中的当前行整数值被编译。 |
__FILE__ | 字面上包含源文件的假定名字符串被编译。 |
__DATE__ | 字符串的形式包含在编译过程的开始日期“嗯月日年”的文字。 |
__TIME__ | 一个字符串形式的文字为“hh:mm:ss的”包含该编译过程开始的时间。 |
__cplusplus | 一个整数值。所有的C ++编译器都定义为某个值这个常数。它的值取决于编译器支持标准的版本:
199711L :ISO C ++ 1998/2003201103L :ISO C ++ 2011 不符合标准的编译器定义这个常量作为最多五位数长一些价值。需要注意的是很多编译器不完全符合,因此将有定义为既没有上述值这个常量。 |
__STDC_HOSTED__ | 1 如果实现是一个托管实现(提供所有标准头) 0 ,否则。 |
下面的宏定义可选,通常取决于功能是否可用:
宏 | 值 |
---|
__STDC__ | 在C:如果定义为1 ,实施符合C标准。 在C ++:实现定义。 |
__STDC_VERSION__ | 在C:
199401L :ISO C 1990年,Ammendment 1199901L :ISO C 1999年201112L :ISO C 2011 在C ++:实现定义。 |
__STDC_MB_MIGHT_NEQ_WC__ | 1 如果多字节编码可能给一个字符字符文字不同的值 |
__STDC_ISO_10646__ | 形式的值yyyymmL ,指定Unicode标准的日期后的编码wchar_t 字符 |
__STDCPP_STRICT_POINTER_SAFETY__ | 1 如果实现了严格的安全指针(见get_pointer_safety ) |
__STDCPP_THREADS__ | 1 如果程序可具有一个以上的线程 |
具体实现可以定义额外的常量。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
| // standard macro names
#include <iostream>
using namespace std;
int main()
{
cout << "This is the line number " << __LINE__;
cout << " of file " << __FILE__ << ".\n";
cout << "Its compilation began " << __DATE__;
cout << " at " << __TIME__ << ".\n";
cout << "The compiler gives a __cplusplus value of " << __cplusplus;
return 0;
} | 这是文件/home/jay/stdmacronames.cpp的行号7。
它开始编制2005年11月1日10点12分29秒。
编译器给出了1 __cplusplus值 |
|