c++宏使用总结【转】
C/C++中宏总结C程序的源代码中可包括各种编译指令,这些指令称为预处理命令。虽然它们实际上不是C语言的一部分,但却扩展了C程序设计的环境。
ANSI标准定义的C语言预处理程序包括下列命令:
#define,#error,#include,#if,#else,#elif,#endif,#ifdef,#ifndef,#undef,#line,#pragma等。所有的预处理命令都已符号#开头。
1、#define
命令#define定义了一个标识符及一个串。在源程序中每次遇到该标识符时,均以定义的串代换它。ANSI标准将标识符定义为宏名,将替换过程称为宏替换。命令的一般形式为:
#define identifier string
- 该语句没有分号。标识符和字符串之间可以有任意个空格,但是一旦字符串开始,只能由新的一行结束。
- 宏名称定义后,即可成为其他宏名定义的一部分。
- 宏替换仅仅是以字符串代替标识符,前提是宏标识符必须独立的识别出来,否则不进行替换。比如#define 123 a number就不能独立识别。
- 若字符串长于一行,可以在行末尾使用‘\’续行。
2、#error
处理器命令#error强迫编译程序停止编译,主要用于程序调试。
3、#include
命令#include使编译程序将另一源文件嵌入带有#include的源文件,被读入的源文件必须用双引号或尖括号括起来。
- 如果显式路径名为文件标识符的一部分,则仅在子目录中搜索被嵌入文件。即包含路径只搜索路径内。
- 如果文件名用双引号括起来,则首先检索当前工作目录。如果未发现文件,则在命令行中说明的所有目录中搜索。如果仍未发现文件,则搜索实现时定义的标准目录。
- 如果没有显式路径名且文件名被尖括号括起来,则首先在编译命令行中的目录内检索。
4、条件编译指令
有几个命令可对程序源代码的各部分有选择地进行编译,该过程称为条件编译。商业软件公司广泛应用条件编译来提供和维护某一程序的许多顾客版本。
#if、#else,#elif及#endif #if的一般含义是如果#if后面的常量表达式为true,则编译它与#endif之间的代码,否则跳过这些代码。命令#endif标识一个#if块的 结束。
#if constant-expression
statement sequence
#endif
跟在#if后面的表达式在编译时求值,因此它必须仅含常量及已定义过的标识符,不可使用变量。表达式不许含有操作符sizeof(sizeof也是编译时求值)。
if、else、elif(elseif)、endif与代码中的条件判断类似。
# ifdef 和# ifndef
条件编译的另一种方法是用#ifdef与#ifndef命令,它们分别表示"如果有定义"及"如果无定义"。
# ifdef的一般形式是:
# ifdef macroname
statement sequence
#endif
#ifdef与#ifndef可以用于#if、#else,#elif语句中,但必须与一个#endif。
5、undef
命令#undef 取消其后那个前面已定义过的宏名定义。一般形式为:
#undef macroname
6、#line
命令# line改变__LINE__与__FILE__的内容,它们是在编译程序中预先定义的标识符。命令的基本形式如下:
# line number["filename"]
其中的数字为任何正整数,可选的文件名为任意有效文件标识符。行号为源程序中当前行号,文件名为源文件的名字。命令# line主要用于调试及其它特殊应用。
7、预定义的宏名
ANSI标准说明了C中的五个预定义的宏名。它们是:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序也许还提供其它预定义的宏名。
__LINE__及__FILE__宏指令在有关# line的部分中已讨论,这里讨论其余的宏名。
__DATE__宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。
源代码翻译到目标代码的时间作为串包含在__TIME__中。串形式为时:分:秒。
如果实现是标准的,则宏__STDC__含有十进制常量1。如果它含有任何其它数,则实现是非标准的。编译C++程序时,编译器自动定义了一个预处理名
字__cplusplus,而编译标准C时,自动定义名字__STDC__。
注意:宏名的书写由标识符与两边各二条下划线构成。
8、C、C++宏体中出现的#,#@,##
宏体中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个
双引号。
而##被称为连接符(concatenator),用来将两个Token连接为一个Token。注意这里连接的对象是Token就行,而不一定是宏的变
量。比如你要做一个菜单项命令名和函数指针组成的结构体的数组,并且希望在函数名和菜单项命令名之间有直观的、名字上的关系。那就可以使用:宏参数##
固定部分。当然还可以n个##符号连接 n+1个Token,这个特性也是#符号所不具备的。
#@的功能是将其后面的宏参数进行字符化。
9、C宏中的变参...
...在C宏中称为Variadic Macro,也就是变参宏。比如:
#define myprintf(templt,...) fprintf(stderr,templt,__VA_ARGS__)
或者#define myprintf(templt,args...) fprintf(stderr,templt,args)
第一个宏中由于没有对变参起名,我们用默认的宏__VA_ARGS__来替代它。第二个宏中,我们显式地命名变参为args,那么我们在宏定义中就可以
用args来代指变参了。同C语言的stdcall一样,变参必须作为参数表的最后有一项出现。当上面的宏中我们只能提供第一个参数templt时,C
标准要求我们必须写成: myprintf(templt,);的形式。这时的替换过程为:myprintf("Error!\n",);替换为:
fprintf(stderr,"Error!\n",).
这是一个语法错误,不能正常编译。这个问题一般有两个解决方法。首先,GNU CPP提供的解决方法允许上面的宏调用写成:
myprintf(templt);而它将会被通过替换变成: fprintf(stderr,"Error!\n",);
很明显,这里仍然会产生编译错误(非本例的某些情况下不会产生编译错误)。除了这种方式外,c99和GNU CPP都支持下面的宏定义方式:
#define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__)
这时,##这个连接符号充当的作用就是当__VAR_ARGS__为空的时候,消除前面的那个逗号。那么此时的翻译过程如下:
myprintf(templt);被转化为: fprintf(stderr,templt);
这样如果templt合法,将不会产生编译错误。
c++宏使用总结【转】的更多相关文章
- Visual Studio 宏的高级用法
因为自 Visual Studio 2012 开始,微软已经取消了对宏的支持,所以本篇文章所述内容只适用于 Visual Studio 2010 或更早期版本的 VS. 在上一篇中,我已经介绍了如何编 ...
- VC 中与字符串相关的宏 _T、TEXT,_TEXT、L 的作用
CSDN原博文:http://blog.csdn.net/houkai363/article/details/8134787 遇到了:不能将参数 1 从“const char [5]”转换为“LPCT ...
- 【转】linux内核中writesb(), writesw(), writesl() 宏函数
writesb(), writesw(), writesl() 宏函数 功能 : writesb() I/O 上写入 8 位数据流数据 (1字节) writesw() I/O 上写入 16 ...
- c++宏定义命令
在程序开始以#开头的命令,他们是预编译命令.有三类预编译命令:宏定义命令.文件包含命令.条件编译命令:今天聊聊宏定义: 宏定义命令将一个标识符定义为一个字符串,源程序中的该标识符均以指定的字符串来代替 ...
- dll导入导出宏定义,出现“不允许 dllimport 函数 的定义”的问题分析
建立dll项目后,在头文件中,定义API宏 #ifndef API_S_H #define API_S_H ...... #ifndef DLL_S_20160424 #define API _dec ...
- VC++/MFC 最常用宏和指令
1.#include指令 包含指定的文件,最基本的最熟悉的指令,编程中不得不用,包含库文件用双尖括号,包含自定义头文件用双引号. 2.#define指令 预定义,通常用它来定义常量(包括无参量与 ...
- [Sass]混合宏的参数
[Sass]混合宏的参数--传一个不带值的参数 Sass 的混合宏有一个强大的功能,可以传参,那么在 Sass 中传参主要有以下几种情形: A) 传一个不带值的参数 在混合宏中,可以传一个不带任何值的 ...
- [Sass]混合宏
[Sass]混合宏-声明混合宏 如果整个网站中有几处小样式类似,比如颜色,字体等,在 Sass 可以使用变量来统一处理,那么这种选择还是不错的.但当你的样式变得越来越复杂,需要重复使用大段的样式时,使 ...
- BOOST_AUTO宏
在boost中,有个非常不错的宏BOOST_AUTO(),它的作用是自动给var定义类型,适合function()函数返回的值的类型. int function() { ; } main() { BO ...
- C++预定义宏
C/C++宏体中出现的#,#@,##: - #的功能是将其后面的宏参数进行字符串化操作(stringfication),就是对它所引用的宏变量通过替换后在其左右各加上一个双引号 -##被称为连接符(c ...
随机推荐
- 将word文件快速转换成表格的技巧
最近烦心事还真是很多,世界买家网最近就遇到了很多烦心事. 从www.buyerinfo.biz网站中的数据导出为csv格式的文件,我导出了buyer的数据,那怎么把它制作成表格呢? 找了下,发现还是比 ...
- Linq中关键字的作用及用法
Linq中关键字的作用及用法 1.All:确定序列中的所有元素是否都满足条件.如果源序列中的每个元素都通过指定谓词中的测试,或者序列为空,则为 true:否则为 false. Demo: 此示例使用 ...
- 在Win7 64位操作系统下安装Oracle 10g
参见网址http://www.cnblogs.com/newstar/archive/2010/12/01/1878026.html 1.下载安装程序,可以到这个网址去下载 http://www.or ...
- 记AppStore 被打回的经历
在快驰已然有半年时间之久. 见证了“快货运”产品,在不断摧残的环境中成长着. 两个人,将一个产品亲手从无到有的构建,有过心酸.有过累和有过憔悴,但当“快货运”开始上APP store时,又让人觉得开 ...
- 工厂方法模式与IoC/DI
IoC——Inversion of Control 控制反转 DI——Dependency Injection 依赖注入 1:如何理解IoC/DI 要想理解上面两个概念,就必须搞清 ...
- jquery中的children()和contents()的区别
1.children()只会返回元素节点 2.contents()还可以返回文本节点
- The first day to learn Englisht
IF you want to go fast,to alone. IF you want to go far,go with others.
- 将页面上的内容导出到Excel
<asp:Button ID="lkbExport" runat="server" Name="Save" Text="导出 ...
- 【转】C#线程同步示例
using System; using System.Threading; // 银行帐户类 class Account { int balance; ...
- SQL Server 2005 处理交叉表
假设有一个表如下: 日期 时间 售货金额 2006-01-02 早上 50 2006-01-02 中午 20 2006-01-02 晚上 30 2006-01-02 零晨 40 2006-01-03 ...