4

我在一个内核代码中找到了这个宏.. 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);
4

3 回答 3

9

双哈希用于将两个标记连接在一起:

#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 内核中的大写标识符通常是宏)。它在几个地方定义,其中之一是:

#define __IO_PREFIX             generic

现在让我们看看采取了哪些步骤来扩展原始语句:

  1. 展开__IO_PREFIX
    返回 IO_CONCAT(通用,readl)(地址);
    
  2. 展开IO_CONCAT(...)
    返回_IO_CONCAT(通用,readl)(地址);
    
  3. 展开_IO_CONCAT(...)
    返回generic_readl(地址);
    
于 2012-08-30T14:13:53.920 回答
5

那是令牌粘贴。它将标记连接在一起。所以IO_CONCAT(foo,bar)会扩展到foo_bar.

它在 C99 的 §6.10.3.3 中定义:

如果在类函数宏的替换列表中,参数紧跟在##预处理标记之前或之后,则将参数替换为相应参数的预处理标记序列;但是,如果参数不包含预处理标记,则该参数将替换为地标预处理标记。)

对于类对象和类函数宏调用,在重新检查替换列表以替换更多宏名称之前,##替换列表(不是来自参数)中的预处理标记的每个实例都被删除,并且前面的预处理标记被连接使用以下预处理令牌。Placemarker 预处理令牌经过特殊处理:两个 placemarker 的串联产生单个 placemarker 预处理令牌,placemarker 与非placemarker 预处理令牌的串联产生非placemarker 预处理令牌。如果结果不是有效的预处理标记,则行为未定义。生成的令牌可用于进一步的宏替换。运算符的评估顺序##未指定。

于 2012-08-30T14:04:03.650 回答
5

那是预处理器令牌连接运算符

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

于 2012-08-30T14:04:25.097 回答