define宏定义中的#,##,@#及\符号
define宏定义中的#,##,@#及\符号
在#define中,标准只定义了#和##两种操作。#用来把参数转换成字符串,##则用来连接两个前后两个参数,把它们变成一个字符串。
1、# (stringizing)字符串化操作符。其作用是:将宏定义中的传入参数名转换成用一对双引号括起来参数名字符串。其只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。
如:
#define example(instr) printf("the input string is:\t%s\n",#instr)
#define example1(instr) #instr
当使用该宏定义时:
example(abc); 在编译时将会展开成:printf("the input string is:\t%s\n","abc");
string str=example1(abc); 将会展成:string str="abc";
注意:
对空格的处理
a。忽略传入参数名前面和后面的空格。
如:str=example1( abc ); 将会被扩展成 str="abc";
b.当传入参数名间存在空格时,编译器将会自动连接各个子字符串,用每个子字符串中只以一个空格连接,忽略其中多余一个的空格。
如:str=exapme( abc def); 将会被扩展成 str="abc def";
2、## (token-pasting)符号连接操作符
宏定义中:参数名,即为形参,如#define sum(a,b) (a+b);中a和b均为某一参数的代表符号,即形式参数。
而##的作用则是将宏定义的多个形参成一个实际参数名。
如:
#define exampleNum(n) num##n
int num9=9;
使用:
int num=exampleNum(9); 将会扩展成 int num=num9;
注意:
1.当用##连接形参时,##前后的空格可有可无。
如:#define exampleNum(n) num ## n 相当于 #define exampleNum(n) num##n
2.连接后的实际参数名,必须为实际存在的参数名或是编译器已知的宏定义
// preprocessor_token_pasting.cpp
#include <stdio.h>
#define paster( n ) printf_s( "token" #n " = %d", token##n )
int token9 = 9;
int main()
{
paster(9);
}
运行结果:
token9 = 9
3、@# (charizing)字符化操作符。
只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。作用是将传的单字符参数名转换成字符,以一对单引用括起来。
#define makechar(x) #@x
a = makechar(b);
展开后变成了:
a= 'b';
4、\ 行继续操作符
当定义的宏不能用一行表达完整时,可以用"\"表示下一行继续此宏的定义。
注意:换行不能切断单词,只能在空格的地方进行。
宏定义的特殊符号# ## - [C++]
1. 利用宏参数创建字符串:# 运算符
在类函数宏(function-like macro)的替换部分中,“#”符号用作一个预处理运算符,它可以把语言符号(token)转化为字符串。例如,如果 x 是一个宏参量,那么 #x 可以把参数名转化为相应的字符串。该过程称为字符串化。
说明:类函数宏就是带参数的宏。类函数宏的定义中,用圆括号括起来一个或多个参数,随后这些参数出现在替换部分。
#include <stdio.h>
#define PSQR(x) printf("The square of " #x " is %d. \r\n", (x) * (x))
int main(void)
{
int y = 5;
PSQR(y);
PSQR(2 + 4);
return 0;
}
// 输出:
The square of y is 25. // 用 "y" 代替 #x
The square of 2 + 4 is 36. // 用 "2 + 4" 代替 #x
#include <stdio.h>
#define PSQR(x) printf("The square of " #x " is %d. \r\n", (x) * (x))
int main(void)
{
int y = 5;
PSQR(y);
PSQR(2 + 4);
return 0;
}
// 输出:
The square of y is 25. // 用 "y" 代替 #x
The square of 2 + 4 is 36. // 用 "2 + 4" 代替 #x
#define STRING2(x) #x
#define STRING(x) STRING2(x)
#define WQ wangqi
#pragma message(STRING2(WQ)) // WQ(字符串)
#pragma message(STRING(WQ)) // wangqi(字符串)
#define STRING2(x) #x
#define STRING(x) STRING2(x)
#define WQ wangqi
#pragma message(STRING2(WQ)) // WQ(字符串)
#pragma message(STRING(WQ)) // wangqi(字符串)
2. 预处理器的粘合剂:## 运算符
和 # 运算符一样,## 运算符可以用于类函数宏的替换部分。另外,## 运算符还可用于类对象宏(object-like macro)的替换部分。这个运算符把两个语言符号组合成单个语言符号。例如,可以定义如下宏:
#define XNAME(n) x ## n
#define XNAME(n) x ## n
宏调用 XNAME(4) 会展开成 x4 。
说明:类对象宏就是用来代表值的宏。如,#define PI 3.141593 中的PI。
#include <stdio.h>
#define XNAME(n) x ## n
#define PRINT_XN(n) printf("x" #n " = %d\r\n", x ## n);
int main(void)
{
int XNAME(1) = 14; // 变为 int x1 = 14;
int XNAME(2) = 20; // 变为 int x2 = 20;
PRINT_XN(1) // 变为 printf("x1 = %d\r\n", x1);
PRINT_XN(2) // 变为 printf("x2 = %d\r\n", x2);
return 0;
}
// 输出:
x1 = 14
x2 = 20
#include <stdio.h>
#define XNAME(n) x ## n
#define PRINT_XN(n) printf("x" #n " = %d\r\n", x ## n);
int main(void)
{
int XNAME(1) = 14; // 变为 int x1 = 14;
int XNAME(2) = 20; // 变为 int x2 = 20;
PRINT_XN(1) // 变为 printf("x1 = %d\r\n", x1);
PRINT_XN(2) // 变为 printf("x2 = %d\r\n", x2);
return 0;
}
// 输出:
x1 = 14
x2 = 20
#define __T(x) L ## x
#define _T(x) __T(x)
#define _TEXT(x) __T(x)
#define WQ "wangqi"
#pragma message(__T(WQ)) // LWQ (标识符)
wcout << _T(WQ); // wangqi(宽字节字符串)
#define __T(x) L ## x
#define _T(x) __T(x)
#define _TEXT(x) __T(x)
#define WQ "wangqi"
#pragma message(__T(WQ)) // LWQ (标识符)
wcout << _T(WQ); // wangqi(宽字节字符串)
3. 语言符号
从技术方面看,系统把宏的主体当作语言符号(token)类型字符串,而不是字符型字符串。C 预处理器中的语言符号是宏定义主体中的单独的“词(word)”。用空白字符把这些词分开。例如:
#define FOUR 2*2
#define FOUR 2*2
这个定义中有一个语言符号:即序列 2*2 。但是:
#define SIX 2 * 3
#define SIX 2 * 3
这个定义中有三个语言符号:2、* 和 3 。
在处理主体中的多个空格时,字符型字符串和语言符号型字符串采用不同方法。考虑下面的定义:
#define EIGHT 4 * 8
#define EIGHT 4 * 8
把主体解释为字符型字符串时,预处理器用 4 * 8 替换 EIGHT 。也就是说,额外的空格也当作替换文本的一部分。但是,当把主体解释为语言符号类型时,预处理器用由单个空格分隔的三个语言符号,即 4 * 8 来替换 EIGHT 。 换句话说,用字符型字符串的观点看,空格也是主体的一部分;而用语言符号字符串的观点看,空格只是分隔主体中语言符号的符号。在实际应用中,有些 C 编译器把宏主体当作字符串而非语言符号。在比这个实例更复杂的情况下,字符与语言符号之间的差异才有实际意义。
顺便提一下,C 编译器处理语言符号的方式比预处理器的处理方式更加复杂。编译器能理解 C 的规则,不需要用空格来分隔语言符号。例如,C 编译器把 2*2 当作三个语言符号。原因是 C 编译器认为每个 2 都是一个常量,而 * 是一个运算符。
define宏定义中的#,##,@#及\符号的更多相关文章
- #define宏定义中## #@ # \ 符号使用
C/C++ 宏命令的神奇用法. 先看下面三条语句: #define Conn(x,y) x##y#define ToChar(x) #@x#define ToString(x) ...
- 宏定义中的##操作符和... and _ _VA_ARGS_ _
1.Preprocessor Glue: The ## Operator 预处理连接符:##操作符 Like the # operator, the ## operator can be used i ...
- typedef 类型重命名 和 #define 宏定义(1)
http://www.blogjava.net/jasmine214--love/archive/2010/11/29/339307.html 在现实生活中,信息的概念可能是长度,数量和面积等.在C语 ...
- #define宏定义
1 #define的概念 #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本. 该命令有两种格式:一种是简单的宏定义, ...
- iOS define 宏定义 和 const定义常量区别
const const 是c++中的修饰符. c++中常用来定义常量,修饰左值. #define 宏定义语句, 在预处理阶段直接做文本替换,不做类型检查. 它们之间的最大区别: 1. 对于co ...
- iOS 7:漫谈#define 宏定义
#define宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开 ...
- iOS 7:漫谈#define 宏定义(转)
iOS :漫谈#define 宏定义 #define宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步 ...
- 面试问题5:const 与 define 宏定义之间的区别
问题描述:const 与 define 宏定义之间的区别 (1) 编译器处理方式不同 define宏是在预处理阶段展开: const常量是编译运行阶段使用: (2) 类型和安全检查不同 ...
- 宏定义中使用do{}while(0)的好处 (转载)
宏定义中使用do{}while(0)的好处 #define MACRO_NAME(para) do{macro content}while(0) 的格式,总结了以下几个原因: 1,空的宏定 ...
随机推荐
- ZOJ 3872--解题报告
题目相关: 3872相关链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5520 Edward拥有一组数列. 其定义了Be ...
- C++ Primer : 第十二章 : 动态内存之shared_ptr类实例:StrBlob类
StrBlob是一个管理string的类,借助标准库容器vector,以及动态内存管理类shared_ptr,我们将vector保存在动态内存里,这样就能在多个对象之间共享内存. 定义StrBlob类 ...
- Hibernate设置派生属性(formula)
一.Customer中包含的字段: private static final long serialVersionUID = 1L; private Integer id; private ...
- URAL 1934 Black Spot(最短路)
Black Spot Time limit: 1.0 secondMemory limit: 64 MB Bootstrap: Jones's terrible leviathan will find ...
- Json学习篇
JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分语言的支持),从而可以在不同平台间进行 ...
- poj1511 最短路
题意:与poj3268一样,所有人需要从各点到一点再从一点到各点,求最短路总和. 与poj3268一样,先正向建图跑 dijkstra ,得到该点到其他所有各点的最短路,即这些人回去的最短路,再用反向 ...
- 越狱Season 1-Episode 7: Riots, Drills and the Devil: Part 2
Season 1, Episode 7: Riots, Drills and the Devil: Part 2 -Pope: Belick, get those guys in line guy: ...
- 【BZOJ1008】【HNOI2008】越狱
以前水过的水题 原题: 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 1& ...
- C++@冒号(:)和双冒号(::)的用法
转自:http://blog.csdn.net/zimingjushi/article/details/6549390 1.冒号(:)用法 (1)表示机构内位域的定义(即该变量占几个bit空间) ty ...
- LINQ及EntityFramework何时从数据库返回数据,备忘
Generally speaking, LINQ queries are executed when the application code processes data (for instance ...