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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6503586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:17:06  来源:igfitidea点击:

What does ## in a #define mean?

c++cc-preprocessor

提问by Dante May Code

What does this line mean? Especially, what does ##mean?

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

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

Edit:

编辑:

A little bit confused still. What will the result be without ##?

还是有点糊涂。没有结果会##怎样?

采纳答案by ybungalobill

A little bit confused still. What will the result be without ##?

还是有点糊涂。如果没有##,结果会怎样?

Usually you won't notice any difference. But there isa difference. Suppose that Somethingis of type:

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

struct X { int x; };
X Something;

And look at:

看看:

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

Without token concatenation operator ##, it expands to:

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

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

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

With token concatenation it expands to:

通过令牌连接,它扩展为:

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

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

It's important to remember that the preprocessor operates on preprocessor tokens, noton text. So if you want to concatenate two tokens, you must explicitly say it.

重要的是要记住预处理器对预处理器标记进行操作,而不是对文本进行操作。所以如果你想连接两个令牌,你必须明确地说出来。

回答by Nawaz

##is called token concatenation, used to concatenate two tokens in a macro invocation.

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

See this:

看到这个:

回答by fyr

One very important part is that this token concatenation follows some very special rules:

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

e.g. IBM doc:

例如 IBM 文档:

  • Concatenation takes place before any macros in arguments are expanded.
  • If the result of a concatenation is a valid macro name, it is available for further replacement even if it appears in a context in which it would not normally be available.
  • If more than one## operator and/or # operator appears in the replacement list of a macro definition, the order of evaluation of the operators is not defined.
  • 连接发生在参数中的任何宏被扩展之前。
  • 如果连接的结果是一个有效的宏名称,即使它出现在通常不可用的上下文中,它也可用于进一步替换。
  • 如果在宏定义的替换列表中出现多个## 运算符和/或# 运算符,则未定义运算符的求值顺序。

Examples are also very self explaining

例子也很自我解释

#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

With output:

有输出:

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

Source is the IBM documentation. May vary with other compilers.

来源是 IBM 文档。可能因其他编译器而异。

To your line:

到您的线路:

It concatenates the variable attribute to the "Something." and adresses a variable which is logically anded which gives as result if Something.variable has a flag set.

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

So an example to my last comment and your question(compileable with g++):

所以我最后一条评论和你的问题的一个例子(可以用 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 <iostream>
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;
};

回答by Balanivash

According to Wikipedia

根据维基百科

Token concatenation, also called token pasting, is one of the most subtle — and easy to abuse — features of the C macro preprocessor. Two arguments can be 'glued' together using ## preprocessor operator; this allows two tokens to be concatenated in the preprocessed code. This can be used to construct elaborate macros which act like a crude version of C++ templates.

标记串联,也称为标记粘贴,是 C 宏预处理器最微妙且易于滥用的功能之一。可以使用 ## 预处理器运算符将两个参数“粘合”在一起;这允许在预处理代码中连接两个标记。这可用于构建复杂的宏,其作用类似于 C++ 模板的粗略版本。

Check Token Concatenation

检查令牌串联

回答by Chethan

lets consider a different example:

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

consider

考虑

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

without the ##, clearly the preprocessor cant see xand yas separate tokens, can it?

没有##,显然预处理器无法看到x并且y作为单独的标记,可以吗?

In your example,

在你的例子中,

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

##is simply not needed as you are not making any new identifier. In fact, compiler issues "error: pasting "." and "variable" does not give a valid preprocessing token"

##根本不需要,因为您没有制作任何新标识符。实际上,编译器会发出“错误:粘贴“。”和“变量”没有给出有效的预处理标记”

回答by sharkin

This is not an answer to your question, just a CW post with some tips to help you explore the preprocessor yourself.

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

The preprocessing step is actually performed prior to any actual code being compiled. In other words, when the compiler starts building your code, no #definestatements or anything like that is left.

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

A good way to understand what the preprocessor does to your code is to get hold of the preprocessed output and look at it.

了解预处理器对您的代码做了什么的一个好方法是获取预处理输出并查看它。

This is how to do it for Windows:

这是为 Windows 执行此操作的方法:

Create a simple file called test.cppand put it in a folder, say c:\temp. Mine looks like this:

创建一个名为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;
}

Not very useful, but simple. Open the Visual studio command prompt, navigate to the folder and run the following commandline:

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

c:\temp>cl test.cpp /P

So, it's the compiler your running (cl.exe), with your file, and the /P option tells the compiler to store the preprocessed output to a file.

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

Now in the folder next to test.cpp you'll find test.i, which for me looks like this:

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

#line 1 "test.cpp"


int main()
{
  int my_intdog = 0;
  char my_chardog = 'a';

  return 0;
}

As you can see, no #defineleft, only the code it expanded into.

如您所见,没有留下#define,只有它展开的代码。