来自内核代码的这个宏中##的含义是什么

时间:2012-08-30 14:01:18

标签: 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

我无法理解这个含义。有人知道吗?

修改:

然后在这里返回什么

  return IO_CONCAT(__IO_PREFIX,readl)(addr);

3 个答案:

答案 0 :(得分:8)

Double hash用于将两个标记连接在一起:

#define CONCAT(a,b) a ## b

CONCAT(x, y) # Gives 'xy'

但是,如果传递的参数之一是宏本身,这种天真的实现不起作用:

#define Z y
CONCAT(x, Z) # Gives 'xZ', not 'xy' as one might expect

这就是你的问题中使用宏间接的原因:

#define CONCAT(a,b)  __CONCAT(a,b)
#define __CONCAT(a,b) a ## b

#define Z y
CONCAT(x, Z) # Gives 'xy' 

UPD。

现在考虑一下你要问的具体例子:

return IO_CONCAT(__IO_PREFIX,readl)(addr);

这里__IO_PREFIX显然是一个宏(Linux内核中的大写标识符通常是宏)。它在几个places中定义,其中one为:

#define __IO_PREFIX             generic

现在让我们看看采取了哪些措施来扩展原始声明:

  1. 展开__IO_PREFIX
    return IO_CONCAT(generic,readl)(addr);
    
  2. 展开IO_CONCAT(...)
    return _IO_CONCAT(generic,readl)(addr);
    
  3. 展开_IO_CONCAT(...)
    return generic_readl(addr);
    

答案 1 :(得分:5)

那是token pasting。它将令牌连接在一起。因此IO_CONCAT(foo,bar)会扩展为foo_bar

在C99的§6.10.3.3中定义:

  

如果在类似函数的宏的替换列表中,紧跟在前面的参数   或者后跟一个##预处理令牌,该参数将被相应的替换   参数的预处理标记序列;但是,如果参数包含否   预处理令牌,参数由地标预处理令牌替换   来代替。)

     

对于类似对象和类似函数的宏调用,在替换列表之前   重新检查更多宏名称以替换##预处理令牌的每个实例   在替换列表中(不是从参数中)被删除并进行前面的预处理   token与以下预处理标记连接在一起。 Placemarker   预处理令牌是专门处理的:两个场所标记的串联导致   单个地标标记预处理标记,以及地标标记与标记的连接   非地标标记预处理标记导致非地标标记预处理标记。   如果结果不是有效的预处理标记,则行为未定义。所结果的   令牌可用于进一步的宏替换。 ##运营商的评估顺序   没有具体说明。

答案 2 :(得分:5)

这是预处理器token concatenation operator

  

##' preprocessing operator performs token pasting. When a macro is expanded, the two tokens on either side of each ##'运算符是   合并为一个令牌,然后替换`##'和两个   原始令牌在宏观扩张中。通常两者都会   标识符,或者一个是标识符,另一个是标识符   预处理号码。粘贴后,它们会生成更长的标识符。这个   不是唯一有效的案例。也可以连接两个   数字(或数字和名称,如1.5和e3)成数字。   此外,可以通过令牌形成诸如+ =的多字符运算符   粘贴。