Preprocessor directives:预处理指令,宏定义,行控制,条件包含,错误提示,源文件包含,Pragma
来源:互联网 发布:eia原油库存数据分析 编辑:程序博客网 时间:2024/05/16 10:48
预处理器指令
预处理器指令是代码中的哪些以#开头的行,这些行不是程序的一部分,而是作为预处理器的标识。预处理器在开始编译前检查代码,并且在regularstatements生成代码前处理掉所有的指令。
这些预处理器指令只占代码的一行。一旦检测到换行字符,预处理器指令就结束了。预处理器指令的末尾不需要分号(;)。预处理器指令延伸到多行的唯一方法是在一行的末尾添加反斜杠(\)。
1.宏定义指令(#define,#undef)
你可以使用#define来定义一个预处理器宏,它的语法是:#define identifier replacement
当预处理器遇到这个指令,就会把
identifier
替换成
replacement
。这个
replacement
可以是一个表达式,声明,代码块或者是任何东西。严格的说,预处理器不懂的
C++,
它只是在遇到
identifier
的时候替换成
replacement
。
1
2
3
#define TABLE_SIZE 100inttable1[TABLE_SIZE];
inttable2[TABLE_SIZE];
在预处理器替换了TABLE_SIZE
后,代码就等价于这样:
1
2
inttable1[100];
inttable2[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>usingnamespace
std;
#define getmax(a,b) ((a)>(b)?(a):(b))intmain()
{
int
x=5, y;
y= getmax(x,2);
cout << y << endl;
cout << getmax(7,x) << endl;
return
0;
}
57
定义宏不会影响块结构。宏会一直存在知道遇到#undef预处理器指令:
1
2
3
4
5
#define TABLE_SIZE 100inttable1[TABLE_SIZE];
#undef TABLE_SIZE#define TABLE_SIZE 200inttable2[TABLE_SIZE];
生成的代码如下:
1
2
inttable1[100];
inttable2[200];
函数宏定义在替换串里接受两个特殊的操作符(#和##):
如果#被用在替换串的一个参数前面,这个参数会被替换成一个字符串(就像是被双引号包括一样)。
1
2
#define str(x) #xcout << str(test);
这会被翻译成:
cout <<
"test";
##
可以连接两个参数,两个之间没有空格:
Theoperator ##
concatenatestwo arguments leaving no blank spaces between them:
1
2
#define glue(a,b) a ## bglue(c,out) <<
"test";
翻译结果是:
cout <<
"test";
因为预处理器替换是在C++语法检查之前,所以宏定义是一个巧妙的特性。但是,请注意:因为在很多情况下复杂宏的语法表达和一般的程序员期望的不一样,所以带有复杂宏的代码不易读。
2.条件包含指令(#ifdef,#ifndef, #if, #endif, #else and #elif)
这些指令允许在某个条件满足是包含或者抛弃代码的一部分。#ifdef
只有在宏的参数被定义,无论它的值是什么的时候,允许程序的某一部分被编译:
1
2
3
#ifdef TABLE_SIZEint table[TABLE_SIZE];
#endif
在这种情况下,inttable[TABLE_SIZE];
这行代码只会在
TABLE_SIZE
在之前通过
#define
定义后被编译,
TABLE_SIZE
的值不造成影响。
如果TABLE_SIZE
没有被定义,这行代码就不会被包含进程序编译。
#ifndef
恰恰相反:在#ifndef
和
#endif
指令之间的代码只有在之前没有定义过的情况下被编译。
例如:
1
2
3
4
#ifndef TABLE_SIZE#define TABLE_SIZE 100#endifint table[TABLE_SIZE];
在这种情况下,如果TABLE_SIZE
宏还没有被定义,将会定义一个宏
TABLE_SIZE
,且值为
100.
如果已经存在
TABLE_SIZE
宏,将不会改变宏的值,因为
#define
指令根本没有执行。
#if
,#else
and#elif
(i.e.,"else if") 指令在特定的条件满足时才会使得它们包围的代码被编译。#if
or#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
and#else
连锁指令的整个结构是以
#endif
结束的
。
#ifdef
and#ifndef
的行为可以分别由
#if
或者
#elif
指令加上
defined
和
!defined
来替换
:
1
2
3
4
5
6
#if !defined TABLE_SIZE#define TABLE_SIZE 100#elif defined ARRAY_SIZE#define TABLE_SIZE ARRAY_SIZEint table[TABLE_SIZE];
#endif
3.行控制(#line)
当我们在编译程序时出现了一些错误,编译器会显示包含发生错误的文件名的错误信息和和一个行号,这样能更加准确的找到产生错误的代码。#line
指令
可以帮助我们控制这两件事,当错误发生后我们需要的源文件里的行号和文件名。它的格式如下:#line number"filename"
number规定了下一行代码的行号。接下来的行号会依次递增(步长为1)。"filename"
作为可选参数可以重新定义要显示的文件名。例如:
1
2
#line 20 "assigning variable"int a?;
这段代码会产生一个错误,且会被显示成错误发生在文件"assigningvariable"
,
line20
。
4.错误提示指令(#error)
当发现错误提示指令,就会中止编译,并产生一个以它的参数标识的编译错误:
1
2
3
#ifndef __cplusplus#error A C++ compiler is required!#endif
这个例子会中止编译处理,如果宏__cplusplus
没有被定义
(这个宏名称默认由C++编译器定义)。
5.源文件包含指令 (#include)
当预处理器找到一个#include
指令
,
就会把它替换成头文件或者其他文件的内容。有两种使用
#include
的方式:
1
2
#include <header>#include "file"
第一种情况下,头文件在尖括号中间.这是被用来包含系统提供的头文件的,比如说组成标准库的头文件(iostream,string等)。无论这些头文件是真的文件还是以其他的形式存在是不是实现定义,都应该用这个指令包含进来。
另一种情况是#include
使用引号包含一个文件。这个文件按照实现定义的方式查找,一般包含在当前路径下。如果按照这种方式没有找到文件,编译器就会认为这是头文件包含,就好像把引号换成了尖括号。
Pragma指令 (#pragma)
这个指令用来设定编译器的不同参数。这些参数由平台和你使用的编译器一起决定。你可以查看你的编译器的指南或参考来了解你可以通过#pragma
设置哪些可能的参数
.
如果你的编译器不支持#pragma
的
某个特殊的参数,则它会被忽略而不会产生语法错误。
6.预定义宏名称
下面的宏名称一般会被提前定义好(它们都是以下划线_开始和结束);
macro
value
__LINE__
表示当前正在编译的代码的行号的整形变量(可能不是真正的行号)。
__FILE__
表示当前正在编译的文件的假定文件名(可能不是真正的名字)。
__DATE__
表示编译器开始编译的日期,格式是“Mmmdd yyyy”。
__TIME__
表示编译器开始编译的时间,格式是“hh:mm:ss”。
__cplusplus
一个整形变量。所有的C++编译器都定义了一个这样的常量(值不确定)。它的值取决于编译器支持的标准的版本。
199711L
:ISO C++ 1998/2003201103L
:ISO C++ 2011
不符合标准的编译器往往把这些常量定义为最多不多于5位的长整形数字。有许多编译器都不能完全符合标准,所以他们的常量常常和上面的数字都不一样。
__STD_HOSTED__
1
如果是完全实现(所有的标准头文件都可用)0
其他情况。
以下的宏是可选的,主要依赖于特性是不是可用:
macro
value
__STDC__
在C中:如果定义成1
,那么实现是遵守标准
C
的。
在C++中:实现定义(Implementationdefined)。
__STDC_VERSION__
在C中:
199401L
:ISO C 1990,修订(Amendment) 1199901L
:ISO C 1999201112L
:ISO C 2011
在C++中:实现定义(Implementationdefined)。
__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>usingnamespace
std;
intmain()
{
cout <<
"This is the line number:"
cout << __LINE__<<”.\n”;
cout <<
"This is the file:" cout<< __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.This is the file:/home/jay/stdmacronames.cpp.Its compilation began:Nov 1 2005 at 10:12:29.The compiler gives a __cplusplus value of 1
原资料地址,翻译不当之处,请参看原文,最好能帮忙指正,谢谢
- Preprocessor directives:预处理指令,宏定义,行控制,条件包含,错误提示,源文件包含,Pragma
- 15-预处理指令1-宏定义、条件编译、文件包含
- 预处理指令—宏定义,条件编译,文件包含
- 编译预处理--#include包含指令, #define宏定义指令, #if条件编译指令
- C++编译预处理:宏定义指令、文件包含指令和条件编译指令
- C/C++编译预处理:宏定义指令、文件包含指令、条件编译指令和特殊符号处理
- C++编译预处理:宏定义指令、文件包含指令和条件编译指令
- C++编译预处理:宏定义指令、文件包含指令和条件编译指令
- c语言预处理,包含(宏定义,包含,条件编译)
- IOS开发---C语言-㉑预处理指令:宏定义、条件编译、文件包含
- 黑马程序员--IOS学习笔记总结 预处理指令(宏定义、条件编译、文件包含)
- c-3 预处理指令 宏 条件编译 文件包含
- C语言预处理指令:宏、条件编译、文件包含
- 预处理(宏定义、文件包含、条件编译)
- 预处理 之 宏定义、文件包含、条件编译
- C 预处理(宏定义,文件包含,条件编译)
- 预处理(宏定义、文件包含、条件编译)
- 基础C ,预处理指令,宏定义,文件包含
- 中兴终端事务部内部发生大件事
- js中的hasOwnProperty和isPrototypeOf方法
- Android TV 去掉状态栏
- popus.js弹出模式页面使用方法整理总结
- java学习者的福音----最强JAVA学习线路图以及各阶段配备的学习神器!
- Preprocessor directives:预处理指令,宏定义,行控制,条件包含,错误提示,源文件包含,Pragma
- cocos2d-x之CCAction
- select根据值动态改变选中项
- 用批处理在桌面上创建快捷方式
- Log4net的使用
- 余额宝突破2000亿,基金融资力量不可小觑
- update 语法(相见恨晚)
- 数组长度
- javascript eval函数解析json数据时为什加上圆括号eval("("+data+")")