深入了解宏
来源:互联网 发布:linux装php环境 编辑:程序博客网 时间:2024/06/05 06:11
宏很强大,但我们大多只知道它的替换功能,具体细节总是不清楚,现在时候全面了解它了。
测试方式
参考资料
gcc:
也可以研究一下boost的 MACRO Metaprogram
或看Linux内核的一些宏技巧(比如list定义,once_call, 等等)
宏的细节
形式参数
形参是个有效的 C 标识符, 以逗号和可选的空格分割。
The parameters must be valid C identifiers, separated by commas and optionally whitespace.
实际参数
实参是以逗号和可选的空格分割。这导致了宏的一个缺陷,参数不能是 (a,b) 这样的,boost的foreach宏就受到这个限制。
gcc不受这个限制
The arguments is
例如:
#define CALL(f,a) f a
CALL(printf, ( "%d" , 3 ) ) ==> printf ( "%d" , 3 )
Stringified
#和##只在宏定义中有效。
# stringified 把字符# 右边的 宏参数 转换为字符串 "argument"
example:
#define str(a) #a
Pasted
## pasted 对宏进行参数替换后,去除字符##, 这样就可以实现token合并
example:
#define A abc##def
macro body 展开过程
先进行# stringified操作,再对参数进行替换, 最后执行## pasted 操作。
Simple scan 和 Twice scan
object-like宏 和 function-like但没有参数的宏,或macro body 有 #(stringified ) or ##(pasted) 的macro, 只执行一遍扫描(simple scan)。
否则就要执行两遍扫描。
两遍扫描:
prescan: 对参数进行扫描,并对可以展开的参数进行完全的宏展开。
second scan: 用展开后的参数,对宏体进行展开,对展开后的结果 递归进行 完全的宏展开。
simple scan 执行 second scan 一样的过程。
example:
simple sacn:
递归问题
example:
simple scan:
twice scan:
可变参数的宏
用__VA_ARGS__ 引用可变参数:
#define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__)
使用##__VA_ARGS___ 可以处理0参数的情形
#define eprintf(format, ...) fprintf (stderr, format, ##__VA_ARGS__)
使用其它名字
#define eprintf(format, args...) fprintf (stderr, format , ##args)
宏不允许重复定义
如果两个宏定义基本一致,是不会报错的。
判断宏一致:4条都要满足
1同是object-or function-like
2 宏体中的token要相同(就是空白分割的token)
3 如果有参数,那么形参要相同
4 有相同的空白处(空白字符数不要求一样和像HTML那样)
相同定义,不报错
重复定义错误:
宏调用中使用宏指令
Directives Within Macro Arguments
If, within a macro invocation, that macro is redefined,
then the new definition takes effect in time for argument pre-expansion, but the original definition is still used for argument replacement.
宏调用中重定义那个宏,那么新的定义只在参数展开中起作用,外层宏的宏体展开还是使用原先的定义
多行调用一个宏:
Here is an example illustrating this:
这会导致程序的序号提示错误。
对于宏调用尽量都在一行内完成。
ignore_second_arg (foo (),ignored (), syntax error);
typeof扩展和 embeded statement ({})表达式
减少重复计算,可以使用 gcc的 typeof扩展和 语句表达式
({...}) 对语句进行计算,位于括号中的复合语句的最后一句必需是一个以分号结尾的表达式,它的值将成为这个语句表达式的值。
#define min(X, Y)
简单语句模拟
对于多个语法行的宏定义,建议使用do {...} while (0) 来包裹, 这可以把宏调用当成是一个简单的语句
#define SKIP_SPACES(p, limit)
if (*p != 0)
else ...
将出错。
好的方式是:
#define SKIP_SPACES(p, limit)
- 深入了解宏
- 深入了解lisp(clojure)-宏
- iOS开发深入了解宏定义#define
- 深入了解计算机端口
- 深入了解C语言
- 深入了解C语言
- 深入了解计算机端口
- 深入了解INF文件
- 深入了解路由器
- 深入了解内存
- 深入了解C语言
- 深入了解C语言
- 深入了解DataSet
- 深入了解C语言
- 深入了解JUnit 4
- 深入了解typedef
- 深入了解INF文件
- 深入了解路由器
- C++常考笔试题:不用if,while,do-while,for,打印出所有大于0小于k的整数.函数原型void printLess(int k);
- android源码下加入替换铃声文件,及设置默认铃声
- CMFCToolBar插入组合框
- .net framework3.5安装失败win7_64位
- Struts2得到Request和Session
- 深入了解宏
- C++面向对象基础,以及一些常见面试 改错题。
- ACM/ICPC 2012 天津 B题
- 杂记之TCP/IP协议簇
- HTTP协议是无状态协议,怎么理解?
- Nginx日志监控(包括可视化)工具
- Google C++ Style Guide 的Header File 部分 翻译
- Sparse Table算法
- SQL脚本书写注意事项—性能分析(一)