这是来自linux内核源代码的摘录。什么是stem##
用法?第一次见到c
#define __pcpu_size_call_return(stem, variable) \
({ typeof(variable) pscr_ret__; \
__verify_pcpu_ptr(&(variable)); \
switch(sizeof(variable)) { \
case 1: pscr_ret__ = stem##1(variable);break; \
case 2: pscr_ret__ = stem##2(variable);break; \
case 4: pscr_ret__ = stem##4(variable);break; \
case 8: pscr_ret__ = stem##8(variable);break; \
default: \
__bad_size_call_parameter();break; \
} \
pscr_ret__; \
})
答案 0 :(得分:9)
预处理程序运算符##
提供了一种在宏扩展期间连接实际参数的方法。如果替换文本中的参数与##
相邻,则参数将替换为实际参数,##和周围的空白区域将被删除,并重新扫描结果。例如,宏粘贴连接其两个参数:
#define paste(front, back) front ## back
因此paste(name, 1)
会创建令牌name1
。
答案 1 :(得分:6)
##
运算符是一个预处理程序操作,它将标记粘合在一起形成单个标记。
所以说你想基于一个公共前缀调用两个函数,每次传递一个参数并允许它被更改。
你不能使用:
#define CallBoth(pref,arg) \
{ \
arg = pref A (arg); \
arg = pref B (arg); \
}
因为被替换的pref
和A
(或B
)将是不同的令牌。同样,您不能使用:
#define CallBoth(pref,arg) \
{ \
arg = prefA (arg); \
arg = prefB (arg); \
}
因为不会替换prefA
或prefB
。
要执行此操作,请使用:
#define CallBoth(pref,arg) \
{ \
arg = pref##A(arg); \
arg = pref##B(arg); \
}
并将替换的pref
和A
(或B
)连接成一个令牌。这样,如果你输入:
CallBoth(xyzzy,intVar);
它将被翻译为:
{
intVar = xyzzyA(intVar);
intVar = xyzzyB(intVar);
}
如果没有此功能,则无法使用表示功能名称的单个标记。
如您所引用的文件中的评论中所述:
/ *分支函数将函数拆分为一组函数,这些函数针对处理的对象的不同标量大小调用。 * / 强>
因此,根据给宏的变量大小,它将调用以下之一:
stem1(variable)
stem2(variable)
stem4(variable)
stem8(variable)
其中stem
和variable
作为参数提供给宏。如果这些尺寸的 none 相关,它也会调用__bad_size_call_parameter()
。
所以,打电话:
char char_var;
__pcpu_size_call_return(xyzzy,char_var)
将导致通话:
xyzzy1(char_var):
int int_var;
__pcpu_size_call_return(xyzzy,int_var)
将导致通话:
xyzzy4(int_var)
其中sizeof(int) == 4
。