#和##
来源:互联网 发布:35互联域名管理 编辑:程序博客网 时间:2024/05/02 06:06
宏中的#的功能是将其后面的宏参数进行字符串化操作(Stringizing operator),简单说就是在它引用的宏变量的左右各加上一个双引号。
如定义好#define STRING(x) #x之后,下面二条语句就等价。
char *pChar = "hello";
char *pChar = STRING(hello);
还有一个#@是加单引号(Charizing Operator)
#define makechar(x) #@x
char ch = makechar(b);与char ch = 'b';等价。
但有小问题要注意,宏中遇到#或##时就不会再展开宏中嵌套的宏了。什么意思了?比如使用char *pChar =STRING(__FILE__);虽然__FILE__本身也是一个宏,但编译器不会展开它,所以pChar将指向"__FILE__"而不是你要想的形如"D:\XXX.cpp"的源文件名称。因此要加一个中间转换宏,先将__FILE__解析成"D:\XXX.cpp"字符串。
定义如下所示二个宏:
#define _STRING(x) #x
#define STRING(x) _STRING(x)
再调用下面语句将输出带""的源文件路径
char* pChar = STRING(__FILE__);
printf("%s %s\n", pChar, __FILE__);
可以比较下STRING(__FILE__)与__FILE__的不同,前将带双引号,后一个没有双引号。
再讲下##的功能,它可以拼接符号(Token-pasting operator)。
MSDN上有个例子:
#define paster( n ) printf( "token"#n" = %d\n", token##n )
int token9 = 100;
再调用 paster(9);宏展开后token##n直接合并变成了token9。整个语句变成了
printf( "token""9"" = %d", token9 );
在C语言中字符串中的二个相连的双引号会被自动忽略,于是上句等同于
printf("token9 = %d", token9);。
即输出token9 = 100
#在预编译中也需要用到。
以下内容装载自http://blog.chinaunix.net/uid-317451-id-92652.html
在缺乏引用支持的C语言中,有的时候定义宏几乎成了唯一的选择,虽然有人认为引用代表了一种不怎么明确的语义:不知道参数是否可能会更改,但是如果引用施加于一个语义明确的对象,比如流,那么一切也就无可厚非了。
请看下面一段代码:
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#define get_u16(addr) ({ uint16_t **p = (uint16_t**)&(addr); *(*p)++; })
int main(int argc, char *argv[])
{
uint16_t a[] = {12, 13};
char *ptr = (char*)a;
printf("% " PRIu16 "\n", get_u16(ptr));
printf("% " PRIu16 "\n", get_u16(ptr));
return 0;
}
get_u16的参数被当成了字节流的地址,每次调用它除了返回一个16比特的无符号整形外,数据流也会做相应的改变,可以认为get_u16吃掉并返回了16比特的无符号整形。上面代码运行正常:
gentux ~ # ./a.out
12
13
稍作改变,将ptr改成p,编译后运行:
xiaosuo@gentux ~ $ ./a.out
56984
56976
问题出现了,怎么会是这个结果呢?为了一探究竟我们不妨用cpp将宏展开来看:
int main(int argc, char *argv[])
{
uint16_t a[] = {12, 13};
char *p = (char*)a;
printf("% " "u" "\n", ({ uint16_t **p = (uint16_t**)&(p); *(*p)++; }));
printf("% " "u" "\n", ({ uint16_t **p = (uint16_t**)&(p); *(*p)++; }));
return 0;
}
不难发现,本来应该是宏参数的变量被宏内部的变量覆盖了,根据C对作用域的定义,在宏内部用到的就是自己的变量,实际上我们应该庆幸,上面的代码没有断错误退出,多少给我们留足了面子。
问题的原因找到了,如何解呢?恕在下愚笨,着实没有找到完美的解决方法,只想到了借助编程惯例:除非是库,否则不应该定义以_开始的变量,这样的话,get_u16可以这样定义:
#define get_u16(addr) ({ uint16_t **_p = (uint16_t**)&(addr); *(*_p)++; })
结论:
因为宏毕竟不是函数,所以在其内部定义变量的时候要格外小心,最好在变量名前加上_,以防止覆盖外部变量,造成意外。
- . 和 ->
- || 和&&
- .和::
- “?”和“!”
- #和##
- && 和 ||
- 、和
- #和##
- .//和..//
- 和
- ?和\?
- ./ 和 ../
- #和##
- #、和##
- #和##
- *和&
- <和>
- $*和¥$@
- 实践作业:从键盘输入一系列字符串,写入到某磁盘文件中
- 使用SwingWorker之一
- nyoj115
- 详解yii用户登录体系
- AIX在线自学--只为小伙伴们
- #和##
- javaScript中的假值
- 使用SwingWorker之二
- 手动9 - 安装vsftpd
- Linux SSh scp使用【远程传输】
- ZJU PAT 1018 锤子剪刀布
- 检测数据库中是否存在某一张表
- 第十一篇 ANDROID 系统网络连接和管理机制 .
- 使用SwingWorker之三