Jee*_*tel 4 c macros linux-kernel
我在一个内核代码中找到了这个宏.. http://lxr.free-electrons.com/source/arch/alpha/include/asm/io.h?v=3.0;a=arm#L140
#define IO_CONCAT(a,b) _IO_CONCAT(a,b)
#define _IO_CONCAT(a,b) a ## _ ## b
Run Code Online (Sandbox Code Playgroud)
我无法理解这个含义.有人知道吗?
编辑:
那么它将返回什么
return IO_CONCAT(__IO_PREFIX,readl)(addr);
Run Code Online (Sandbox Code Playgroud)
双哈希用于将两个标记连接在一起:
#define CONCAT(a,b) a ## b
CONCAT(x, y) # Gives 'xy'
Run Code Online (Sandbox Code Playgroud)
但是,如果传递的参数之一是宏本身,这种天真的实现不起作用:
#define Z y
CONCAT(x, Z) # Gives 'xZ', not 'xy' as one might expect
Run Code Online (Sandbox Code Playgroud)
这就是你的问题中使用宏间接的原因:
#define CONCAT(a,b) __CONCAT(a,b)
#define __CONCAT(a,b) a ## b
#define Z y
CONCAT(x, Z) # Gives 'xy'
Run Code Online (Sandbox Code Playgroud)
现在考虑一下你要问的具体例子:
return IO_CONCAT(__IO_PREFIX,readl)(addr);
Run Code Online (Sandbox Code Playgroud)
这__IO_PREFIX显然是一个宏(Linux内核中的大写标识符通常是宏).它定义在几个地方,其中之一是:
#define __IO_PREFIX generic
Run Code Online (Sandbox Code Playgroud)
现在让我们看看采取了哪些步骤来扩展原始声明:
__IO_PREFIX:
return IO_CONCAT(generic,readl)(addr);
IO_CONCAT(...):
return _IO_CONCAT(generic,readl)(addr);
_IO_CONCAT(...):
return generic_readl(addr);
这是一种象征性的粘贴.它将令牌连接在一起.所以IO_CONCAT(foo,bar)会扩展到foo_bar.
它在C99的§6.10.3.3中定义:
如果在类函数宏的替换列表中,参数紧跟在
##预处理标记之前或之后,则该参数将被相应参数的预处理标记序列替换; 但是,如果参数不包含预处理标记,则参数将替换为地标标记预处理标记.)对于类似对象和类似函数的宏调用,在重新检查替换列表以替换更多宏名称之前,
##删除替换列表中的预处理标记的每个实例(不是来自参数),并且连接前面的预处理标记使用以下预处理标记.专门处理地标预处理令牌:两个地方标记的连接导致单个地标标记预处理标记,并且地标标记与非地标标记预处理标记的连接导致非地标标记预处理标记.如果结果不是有效的预处理标记,则行为未定义.生成的令牌可用于进一步的宏替换.##运营商的评估顺序未指定.