-
C/C++
中
##(
两个井号
)
和
#(
一个井号
)
用法
##(
两个井号
)
和
#(
一个井号
)
都是什
么意思
连接符
##(
两个井号
)
不知道什么符
#(
一个井号
)
##
连接符号由两个井号组成,其功能是在带参数的宏定义中
将两个子串
(token)
联接起来,
从而形成一个新的子串。
但它不可以是第一个或者最后一个子串。
所谓的子串
(token)
就是指
编
译器能够识别的最小语法单元。具体的定义在编译原理里有详尽的解释
#
符是把传递过来的参数当成字符串进行替代。
假设程序中已经定义了这样一个带参数的宏:
#define PRINT( n ) printf(
同时又定义了二个整形变量:
int
token9 = 9;
现在在主程序中以下面的方式调用这个宏:
PRINT( 9 );
那么在编译时,上面的这句话被扩展为:
printf(
注意到在这个例子中,
PRINT(9);
中的这个
”9”
被原封不动的当成了一个字符串,与
”token”
连接在了一
起,从而成为了
token9
。而
#n
也被
”9”
所替代。
< br>
可想而知,上面程序运行的结果就是在屏幕上打印出
token9=9
还有点不明白
?!
再来一个例子
:
#define
PRINT( n ) printf(
int
token9 = 9;
int game9 = 99;
调用
:
PRINT(9);
屏幕上打印出
:
token9 =
99
/////////////////////////
//////////////////////////////////////////////////
///////////////////////////
////////////
//////////////////////////////////////////////////
////////////////////////////////////////
C++
中
##(
< br>两个井号
)
和
#(
一个井号
)
用法(转)
C
(和
C++
)中的宏(
Macro
)属于编译器预处理的范畴,属于编译期
概念(而非运行期概
念)。下面对常遇到的宏的使用问题做了简单总结。
关
于
#
和
##
在
C
语言的
宏中,
#
的功能是将其后面的宏参数进行字符串化操作(
Stringfication
),简单
说就
是在对它所引用的宏
变量通过替换后在其左右各加上一个双引
号。比如下面代码中的
宏:
#define WARN_IF(EXP)
do{ if (EXP)
fprintf(stderr,
while(0)
那么实际使用中会出现下面所示的替换过程:
WARN_IF (divider == 0);
被替换为
do {
if (divider == 0)
fprintf(stderr,
} while(0);
这样每次
divider
(除数)为
0
的时候便会在标
准错误流上输出一个提示信息。
<
/p>
而
##
被称为连接符
(
concatenator
)
,
用来将两个
Token
连接为一个
p>
Token
。
注意这里连
< br>
接
的对象是
Token
就行,而不一定是宏的变量。比如你要做一个菜单项命令名和函数指针组
成的结构体的数组,并且希望在函数名和菜单项命令名之间有直观
< br>的、名字上的关系。那
么下面的代码就非常实用:
struct command
{
char * name;
void (*function) (void);
};
#define COMMAND(NAME) { NAME, NAME ##
_command }
// <
/p>
然后你就用一些预先定义好的命令来方便的初始化一个
comma
nd
结构的数组了:
struct command commands[] =
{
COMMAND(quit),
COMMAND(help),
...
}
COMMAND
宏在这里充当一个代
码生成器的作用,这样可以在一定程度上减少代码密度,
间接地也可
以减少不留心所造成的错误。我们还可以
n
个
##
符号连接
n+1
个
Token
,
这
个特性也是
#
符号所不具备的。比如
:
#define
LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d
typedef struct
_record_type
LINK_MULTIPLE(name,company,position,salary);
//
这里这个语句将展开为:
// typedef struct _record_type
name_company_position_salary;
< br>关于
...
的使用
...
在
C
宏中称为
Variadic
Macro
,也就是变参宏。比如:
#define myprintf(templt,...)
fprintf(stderr,templt,__VA_ARGS__)
//
或者
#define
myprintf(templt,args...)
fprintf(stderr,templt,args)
第一个宏中由于没有对变
参起名,<
/p>
我们用默认的宏
__VA_ARGS__
来替代它。
第二个宏中,
我们显式地命名变参为
args
,那么我们在宏定义中就可以用
args
p>
来代指变参了。
同
C
语
言的
stdcall
一样,变参必须作为参数表的最有一项出现。当上面的宏中我们只能提供第一
个参数
templt
时,
C
标准要求我们必须写成:
myprintf(templt,);
的
形式。这时的替换过程为:
myprintf(