42

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 ##?

1

6 Answers 6

24

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

Usually you won't notice any difference. But there is a difference. Suppose that Something is of type:

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, not on text. So if you want to concatenate two tokens, you must explicitly say it.

19

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

See this:

4
  • 3
    In fact it is called token concatenation. I don't think that the documentation for the IBM AIX C/C++ compiler is the best reference! Jun 28, 2011 at 8:26
  • @David: Added this to my answer. Thanks :-) Jun 28, 2011 at 8:28
  • @David: I didn't say IBM AIX C/C++ compiler is the best reference. Best reference is nothing other than the Standard itself. But we give links to other sites anyway, including topics at stackoverflow. Jun 28, 2011 at 8:30
  • Standard is a hopeless reference for a question like this. I'm not sure what a good reference is. Perhaps the text at that IBM AIX reference is good but it's too bad that they can't get the name right! Jun 28, 2011 at 8:36
11

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

e.g. IBM doc:

  • 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.

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.

So an example to my last comment and your question(compileable with 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;
};
3
  • What will the result be without ##? Jun 28, 2011 at 8:41
  • so my test resulted in. Gcc complains about a.##b. a##b evaluates right to a global. a.b evaluates also right to a variable inside the struct instance a.
    – fyr
    Jun 28, 2011 at 9:10
  • I added an example as addition.
    – fyr
    Jun 28, 2011 at 9:34
4

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

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

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:

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

#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:

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.

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

#line 1 "test.cpp"


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

  return 0;
}

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

3

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.

Check Token Concatenation

0
3

lets consider a different example:

consider

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

without the ##, clearly the preprocessor cant see x and y as separate tokens, can it?

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"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.