设为首页 加入收藏

TOP

C语言预处理命令详解(四)
2015-01-22 21:13:20 来源: 作者: 【 】 浏览:146
Tags:语言 处理 命令 详解
NAME) ? {NAME, NAME##_command}
? ? ?然后,就可用一些预先定义好的命令来方便地初始化一个command结构的数组:
?
1 struct command commands[] = {
2 ? ? COMMAND(quit),
3 ? ? COMMAND(help),
4 ? ? //...
5 }
? ? ?COMMAND宏在此充当一个代码生成器的作用,这样可在一定程度上减少代码密度,间接地也可减少不留心所造成的错误。
?
? ? ?还可以用n个##符号连接n+1个Token,这个特性是#符号所不具备的。如:
?
1 #define ?LINK_MULTIPLE(a, b, c, d) ? ? ?a##_##b##_##c##_##d
2 typedef struct record_type LINK_MULTIPLE(name, company, position, salary);
? ? ?这里这个语句将展开为typedef struct record_type name_company_position_salary。
?
? ? ?注意:
?
当用##连接形参时,##前后的空格可有可无。
连接后的实际参数名,必须为实际存在的参数名或是编译器已知的宏定义。
凡是宏定义里有用'#'或'##'的地方,宏参数是不会再展开。如:
1 #define STR(s) ? ? ? #s
2 #define CONS(a,b) ? ?int(a##e##b)
? ? ?则printf("int max: %s\n", STR(INT_MAX))会被展开为printf("int max: %s\n", "INT_MAX")。其中,变量INT_MAX为int型的最大值,其值定义在中。printf("%s\n", CONS(A, A))会被展开为printf("%s\n", int(AeA)),从而编译报错。
?
? ? ?INT_MAX和A都不会再被展开,多加一层中间转换宏即可解决这个问题。加这层宏是为了把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏(如_STR)就能得到正确的宏参数。
?
1 #define _STR(s) ? ? ? ? #s?
2 #define STR(s) ? ? ? ? ?_STR(s) ? ? ? // 转换宏
3 #define _CONS(a,b) ? ? ?int(a##e##b)
4 #define CONS(a,b) ? ? ? _CONS(a,b) ? ?// 转换宏
? ? ?则printf("int max: %s\n", STR(INT_MAX))输出为int max: 0x7fffffff;而printf("%d\n", CONS(A, A))输出为200。
?
? ? ?这种分层展开的技术称为宏的Argument Prescan,参见附录6.1。
?
? ? 【'#'和'##'的一些应用特例】
?
? ? ?1. 合并匿名变量名
?
1 #define ___ANONYMOUS1(type, var, line) ? type ?var##line
2 #define __ANONYMOUS0(type, line) ? ? ? ? ___ANONYMOUS1(type, _anonymous, line)
3 #define ANONYMOUS(type) ? ? ? ? ? ? ? ? ?__ANONYMOUS0(type, __LINE__)
? ? ?例:ANONYMOUS(static int)即static int _anonymous70,70表示该行行号。
?
? ? ?第一层:ANONYMOUS(static int) ?→ ?__ANONYMOUS0(static int, __LINE__)
?
? ? ?第二层: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? → ?___ANONYMOUS1(static int, _anonymous, 70)
?
? ? ?第三层: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? → ?static int _anonymous70
?
? ? ?即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开。
?
? ? ?2. 填充结构
?
复制代码
?1 #define FILL(a) ? {a, #a}?
?2?
?3 enum IDD{OPEN, CLOSE};
?4 typedef struct{
?5 ? ? IDD id;
?6 ? ? const char * msg;?
?7 }T_MSG;
复制代码
? ? ?则T_MSG tMsg[ ] = {FILL(OPEN), FILL(CLOSE)}相当于:
?
1 T_MSG tMsg[] = {{OPEN, ?"OPEN"},
2 ? ? ? ? ? ? ? ? {CLOSE, "CLOSE"}};
? ? ?3. 记录文件名
?
1 #define _GET_FILE_NAME(f) ? ? #f
2 #define GET_FILE_NAME(f) ? ? ?_GET_FILE_NAME(f)
3 static char ?FILE_NAME[] = GET_FILE_NAME(__FILE__);
? ? ?4. 得到一个数值类型所对应的字符串缓冲大小
?
1 #define _TYPE_BUF_SIZE(type) ? sizeof #type
2 #define TYPE_BUF_SIZE(type) ? ?_TYPE_BUF_SIZE(type)
3 char ?buf[TYPE_BUF_SIZE(INT_MAX)];
4 ? ? ?//--> ?char ?buf[_TYPE_BUF_SIZE(0x7fffffff)];
5 ? ? ?//--> ?char ?buf[sizeof "0x7fffffff"];
? ? ?这里相当于:char ?buf[11];?
?
2.3.2.3 字符化操作符@#
? ? ?@#称为字符化操作符(charizing),只能用于有传入参数的宏定义中,且必须置于宏定义体的参数名前。作用是将传入的单字符参数名转换成字符,以一对单引号括起来。
?
1 #define makechar(x) ? ?#@x
2 a = makechar(b);
? ? ?展开后变成a= 'b'。?
?
2.3.2.4 可变参数宏
? ? ?...在C语言宏中称为Variadic Macro,即变参宏。C99编译器标准允许定义可变参数宏(Macros with a Variable Number of Arguments),这样就可以使用拥有可变参数表的宏。
?
? ? ?可变参数宏的一般形式为:
?
? ? ? ? ? ? ? ? ? ? ? ? #define ?DBGMSG(format, ...) ?fprintf (stderr, format, __VA_ARGS__)
?
? ? ?省略号代表一个可以变化的参数表,变参必须作为参数表的最右一项出现。使用保留名__VA_ARGS__ 把参数传递给宏。在调用宏时,省略号被表示成零个或多个符号(包括里面的逗号),一直到到右括号结束为止。当被调用时,在宏体(macro body)中,那些符号序列集合将代替里面的__VA_ARGS__标识符。当宏的调用展开时,实际的参
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 4/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Objective-C中常用的结构体NSRang.. 下一篇编程算法 - 和为s的连续正整数序..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: