#define中的##是什么意思?

这条线是什么意思? 特别是, ##是什么意思?

 #define ANALYZE(变量,标志)((Something。## variable)&(flag))

编辑:

有点困惑。 没有##会有什么结果?

有点困惑。 没有##会有什么结果?

通常你不会注意到任何差异。 但是有区别。 假设Something是类型的:

 struct X { int x; }; X Something; 

看看:

 int X::*p = &X::x; ANALYZE(x, flag) ANALYZE(*p, flag) 

没有令牌连接运算符## ,它扩展为:

 #define ANALYZE(variable, flag) ((Something.variable) & (flag)) ((Something. x) & (flag)) ((Something. *p) & (flag)) // . and * are not concatenated to one token. syntax error! 

使用令牌连接,它扩展为:

 #define ANALYZE(variable, flag) ((Something.##variable) & (flag)) ((Something.x) & (flag)) ((Something.*p) & (flag)) // .* is a newly generated token, now it works! 

重要的是要记住预处理器在预处理器令牌上运行, 而不是在文本上运行。 因此,如果要连接两个令牌,则必须明确说出来。

##称为标记连接,用于在宏调用中连接两个标记。

看到这个:

  • 与##运算符的宏级联

一个非常重要的部分是这个标记连接遵循一些非常特殊的规则:

例如IBM doc:

  • 在扩展参数中的任何宏之前进行连接。
  • 如果连接的结果是有效的宏名称 ,即使它出现在通常不可用的上下文中,它也可用于进一步替换。
  • 如果宏定义的替换列表中出现多个 ##运算符和/或#运算符,则不定义运算符的计算顺序。

例子也很自我解释

 #define ArgArg(x, y) x##y #define ArgText(x) x##TEXT #define TextArg(x) TEXT##x #define TextText TEXT##text #define Jitter 1 #define bug 2 #define Jitterbug 3 

带输出:

 ArgArg(lady, bug) "ladybug" ArgText(con) "conTEXT" TextArg(book) "TEXTbook" TextText "TEXTtext" ArgArg(Jitter, bug) 3 

Source是IBM文档。 可能与其他编译器有所不同。

你的路线:

它将变量属性连接到“Something”。 并且处理一个逻辑上为anded的变量,如果Something.variable设置了一个标志,则该结果给出结果。

这是我上次评论和你的问题的一个例子(用g ++编译):

 // this one fails with a compiler error // #define ANALYZE1(variable, flag) ((Something.##variable) & (flag)) // this one will address Something.a (struct) #define ANALYZE2(variable, flag) ((Something.variable) & (flag)) // this one will be Somethinga (global) #define ANALYZE3(variable, flag) ((Something##variable) & (flag)) #include  using namespace std; struct something{ int a; }; int Somethinga = 0; int main() { something Something; Something.a = 1; if (ANALYZE2(a,1)) cout << "Something.a is 1" << endl; if (!ANALYZE3(a,1)) cout << "Somethinga is 0" << endl; return 1; }; 

根据维基百科

令牌连接(也称为令牌粘贴)是C宏预处理器中最微妙且易于滥用的function之一。 使用##预处理器运算符可以将两个参数“粘合”在一起; 这允许在预处理的代码中连接两个令牌。 这可以用于构建复杂的宏,其行为类似于C ++模板的原始版本。

检查令牌连接

这不是您的问题的答案,只是一篇CW文章,其中包含一些提示,可帮助您自己探索预处理器。

预处理步骤实际上是在编译任何实际代码之前执行的。 换句话说,当编译器开始构建代码时,不会留下#define语句或类似的东西。

理解预处理器对代码的作用的一个好方法是获取预处理的输出并查看它。

这是如何为Windows做到这一点:

创建一个名为test.cpp的简单文件并将其放在一个文件夹中,例如c:\ temp。 我看起来像这样:

 #define dog_suffix( variable_name ) variable_name##dog int main() { int dog_suffix( my_int ) = 0; char dog_suffix( my_char ) = 'a'; return 0; } 

不是很有用,但很简单。 打开Visual Studio命令提示符,导航到该文件夹​​并运行以下命令行:

 c:\temp>cl test.cpp /P 

因此,编译器运行(cl.exe)与您的文件,并且/ P选项告诉编译器将预处理的输出存储到文件中。

现在在test.cpp旁边的文件夹中你会找到test.i,对我来说这看起来像这样:

 #line 1 "test.cpp" int main() { int my_intdog = 0; char my_chardog = 'a'; return 0; } 

如您所见,没有#define ,只有它扩展到的代码。

我们考虑一个不同的例子:

考虑

 #define MYMACRO(x,y) x##y 

没有## ,显然预处理器不能将xy视为单独的令牌,可以吗?

在你的例子中,

 #define ANALYZE(variable, flag) ((Something.##variable) & (flag)) 

由于您没有创建任何新标识符,因此根本不需要## 。 事实上,编译器发出“错误:粘贴”。“和”变量“没有给出有效的预处理令牌”