我在C中定义了一个像这样的宏:
#define SOME_FIELD(_A_,_B_,_C_) \
MyObj[ ## _A_ ## ].somePTR = \
(DWORD_PTR) (buff_ ## _C_ ## _C_ ## _ ## _B_ ## );
我能理解的是,对于索引 A ,我们获得了“somePTR”的一些价值。我的问题是,什么是## <name> ##
表示法,以及如何计算somePTR的值?
我是这样一个宏的新手,所以描述性的解释会非常有用。
答案 0 :(得分:7)
这称为token concatenation。它允许您将参数粘合在一起。
对于您的示例,SOME_FIELD(Param1,Param2,Param3);
扩展如下:
MyObj[Param1].somePTR = (DWORD_PTR) (buff_Param3Param3_Param2);
使用编译器的预处理器自己尝试这一点很容易。您通常不需要编写完全成熟的C程序 - 预处理器通常可以自行调用。
答案 1 :(得分:1)
这是预处理器令牌粘贴
http://msdn.microsoft.com/en-us/library/09dwwt6y(v=vs.80).aspx
它会将实际参数标记复制为字符串文字,因此请将其读取为
// preprocessor_token_pasting.cpp
#include <stdio.h>
#define paster( n ) printf_s( "token" #n " = %d", token##n )
int token9 = 9;
int main()
{
paster(9);
}
答案 2 :(得分:1)
##是concatenation原语,它用于创建符号。
在宏中创建名称很有用:
#define GENERIC_GETTER(f,g) (g->member_ ## f )
GENERIC_GETTER(a,b)
将创建(b->member_a)
(已创建新符号)。如果你不使用尖锐的,它会创建(b->member_ a)
(没有粘在一起)
答案 3 :(得分:1)
通常,##
运算符会连接两个令牌:它需要合法的
左边是令牌,右边是合法令牌,结果是新的
令牌。在你的情况下,宏中的第一行
(MyObj[ ## _A_ ## ].somePtr = \
)是
非法,并导致未定义的行为。大多数实现只是
连接字符串,然后在完成所有字符串后重新声明
替换,所以它会工作,但它不能保证。到目前为止
我在这里可以说,没有必要。在第二行,在
另一方面,您正在生成新令牌。如果你调用宏:
SOME_FIELD(x,y,z);
它将扩展为:
MyObj[x].somePtr = (DWORD_PTR)(buff_zzy);
(我可能会补充说,_A_
,_B_
和_C_
等符号的使用也是
未定义的行为。以下划线开头的符号
大写字母位于实现的名称空间中。)