预处理器指令是程序代码中前面有#符号的行。这些行不是程序语句,而是预处理器的指令。 预处理器在实际开始编译代码之前检查代码,并在由常规语句实际生成任何代码之前解析所有这些指令
预处理器指令只允许一行代码。只要找到一个换行符,预处理器指令就结束。 预处理器指令的末尾不需要分号(;)。预处理器指令可以扩展到多行的唯一方法是 在换行符之前加上一个反斜杠(\)。
当预处理器遇到此指令时,它将替换其余代码中出现的任何标识符。 这个替换可以是一个表达式、一条语句、一个块或简单的任何东西。 预处理器不能理解c++语句,它只是用替换替换任何标识符。
#define TABLE_SIZE 100 int table1[TABLE_SIZE]; int table2[TABLE_SIZE]; |
int table1[100]; int table2[100]; |
#define getmax(a,b) a>b?a:b |
这将用替换表达式代替getmax后面的两个参数,但也用它的标识符替换每个参数,正如你所期望的,如果它是一个函数:
// 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; } |
5 7 |
已定义的宏不受块结构的影响。一个宏会一直持续到使用#undef预处理器指令为止:
#define TABLE_SIZE 100 int table1[TABLE_SIZE]; #undef TABLE_SIZE #define TABLE_SIZE 200 int table2[TABLE_SIZE]; |
int table1[100]; int table2[200]; |
函数宏定义在替换序列中接受两个特殊操作符(#和##): 操作符#后面跟着一个参数名,将被所传递参数的字符串字面值替换(就像用双引号括起来一样):
#define str(x) #x cout << str(test); |
cout << "test"; |
#define glue(a,b) a ## b glue(c,out) << "test"; |
cout << "test"; |
因为预处理器替换发生在任何c++语法检查之前,所以宏定义可能是一个难以捉摸的特性。 但是,要注意:严重依赖复杂宏的代码可读性会降低,因为在许多情况下, 所期望的语法与程序员在c++中期望的普通表达式不同。
#ifdef允许程序的某个部分只有在指定为形参的宏已经定义的情况下才被编译, 而不管它的值是什么。例如:
#ifdef TABLE_SIZE int table[TABLE_SIZE]; #endif |
在本例中,代码行int table[TABLE_SIZE];只有在TABLE_SIZE之前用#define定义过的情况 下才会编译,而与TABLE_SIZE的值无关。如果未定义,则该行将不包含在程序编译中。
#ifndef的作用正好相反:在#ifndef和#endif指令之间的代码只有在指定的标识符没有被预先 定义时才会被编译。例如:
#ifndef TABLE_SIZE #define TABLE_SIZE 100 #endif int table[TABLE_SIZE]; |
在本例中,如果到达这段代码时,TABLE_SIZE宏还没有定义,那么它将被定义为100。 如果它已经存在,它将保持原来的值,因为#define指令不会被执行。
#if, #else和#elif(即"else if")指令用于指定需要满足的某些条件,以便编译它们所包围的代码部分。 #if或#elif后面的条件只能计算常量表达式,包括宏表达式。例如:
#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]; |
#ifdef和#ifndef的行为也可以通过使用在任何#if或#elif指令中分别定义和定义的特殊操作符来实现:
#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"是一个可选参数,允许重定义将显示的文件名。例如:
#line 20 "assigning variable" int a?; |
这段代码将生成一个错误,在文件“赋值变量”第20行中显示为错误。
这个指令在找到它时中止编译过程,生成一个编译错误,可以指定为它的参数:
#ifndef __cplusplus #error A C++ compiler is required! #endif |
如果未定义宏名__cplusplus(此宏名在所有c++编译器中默认定义),则该示例将中止编译过程。
这个指令在本教程的其他部分已经被认真地使用了。当预处理器找到一个#include指令时, 它会用指定头文件或文件的全部内容替换它。#include有两种使用方法:
#include <header> #include "file" |
在第一种情况下,头文件在尖括号<> 之间指定。这用于包含实现提供的头文件, 比如组成标准库的头文件(iostream, string,…)。 头文件是否真的是文件或以其他形式存在是由实现定义的,但在任何情况下, 它们都应该被正确地包含在这个指令中。
第二个#include中使用的语法使用引号,并包含一个文件。该文件搜索它的实现和定义,通常包括当前路径。 在没有找到文件的情况下,编译器将该指令解释为头文件包含,就像尖括号(<>)一样。
该指令用于向编译器指定不同的选项。这些选项是特定于您使用的平台和编译器的。 有关可以使用#pragma定义的可能参数的更多信息,请参阅编译器的手册或参考资料。
如果编译器不支持#pragma的特定参数,它将被忽略——不会生成语法错误。
宏指令 | 值 |
__LINE__ | 表示正在编译的源代码文件中的当前行的整数值。 |
__FILE__ | 被编译的源文件的假定名称的字符串字面值。 |
__DATE__ | 格式为“Mmm dd yyyy”的字符串字面值,其中包含编译过程开始的日期。 |
__TIME__ | 格式为“hh:mm:ss”的字符串字面值,包含编译过程开始的时间。 |
__cplusplus | 一个整数值。所有c++编译器都将这个常量定义为某个值。
它的值取决于编译器支持的标准版本:
|
__STDC_HOSTED__ | 1 如果实现是hosted implementation(具有所有标准头)
0 相反 |
宏指令 | 值 |
__STDC__ | 在C语言中:如果定义为1,则实现符合C语言标准。
在c++中:实现定义。 |
__STDC_VERSION__ | 在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 如果程序可以有多个线程 |
// 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; } |
This is the line number 7 of file /home/jay/stdmacronames.cpp. Its compilation began Nov 1 2005 at 10:12:29. The compiler gives a __cplusplus value of 1 |