Concatination creates invalid preprocessor parameter?

N

Noah Roberts

#define STR_HELPER(s) #s
#define STRINGIZE(s) STR_HELPER(s)

// BOOST_PP_CAT also fails for same reason.
#define MACRO(s1,s2) STRINGIZE(s1 ## s2)

#include <iostream>
int main()
{
std::cout << STRINGIZE(hello(int,int)) << std::endl; // fine.
std::cout << MACRO(hello, (int,int)) << std::endl; // error.
}

Error = concatination of 'hello' and '(' creates invalid preprocessor
token.

Both versions work fine in MSVC++. G++ hates it.

What's the deal? Who's wrong and why?

thx
 
A

Alf P. Steinbach /Usenet

* Noah Roberts, on 11.01.2011 19:15:
#define STR_HELPER(s) #s
#define STRINGIZE(s) STR_HELPER(s)

// BOOST_PP_CAT also fails for same reason.
#define MACRO(s1,s2) STRINGIZE(s1 ## s2)

#include<iostream>
int main()
{
std::cout<< STRINGIZE(hello(int,int))<< std::endl; // fine.
std::cout<< MACRO(hello, (int,int))<< std::endl; // error.
}

Error = concatination of 'hello' and '(' creates invalid preprocessor
token.

Both versions work fine in MSVC++. G++ hates it.

What's the deal? Who's wrong

Visual C++ wrong, g++ right.


Standard requires valid preprocessor token.

This makes it difficult to create directory paths.

Not easy to say why the proprocessor is so incredibly primitive and limited, but
consider that if it were more powerful then it would probably be used more
(which would be undesireable).


Cheers
 
N

Noah Roberts

* Noah Roberts, on 11.01.2011 19:15:

Visual C++ wrong, g++ right.



Standard requires valid preprocessor token.

This makes it difficult to create directory paths.

Not easy to say why the proprocessor is so incredibly primitive and limited, but
consider that if it were more powerful then it would probably be used more
(which would be undesireable).


Cheers


What's invalid about "hello(int,int)"? Why is it accepted when you
don't concat?


Comeau also gobbles it up even in strict, no-extensions mode.
 
N

Noah Roberts

What's invalid about "hello(int,int)"? Why is it accepted when you
don't concat?


Comeau also gobbles it up even in strict, no-extensions mode.

Actually, put a different way, if "hello(int,int)" is not a valid
preprocessor token then why is it able to form one in the first output
line in main()? There's a certain well known and often used C++ UI
library that uses this sort of syntax.
 
A

Alf P. Steinbach /Usenet

* Noah Roberts, on 11.01.2011 21:00:
What's invalid about "hello(int,int)"?

It consists of 6 preprocessing tokens: "hello", "(", "int", ",", "int" and ")".

Why is it accepted when you don't concat?

§16.3/10 effectively defines a preprocessor actual argument as a sequence of
preprocessing tokens. Such a sequence can contain comma tokens within
parentheses, and can otherwise not contain comma tokens.

§16.3.3/3 requires the result of ## to be single preprocessing token, "otherwise
the behavior is undefined".

Comeau also gobbles it up even in strict, no-extensions mode.

Well, with UB it can do anything. ;-)


Cheers & hth.,

- Alf
 
J

James Kanze

Both are right. It's undefined behavior, and anything the
compiler does when there is undefined behavior is right.

G++ solves this by allowing concatenated string literals to be
used as a directory path. Although I can't find anything in the
standard which supports this, it also works with VC++ and with
Sun CC, so I guess it's sort of a defacto standard.
What's invalid about "hello(int,int)"? Why is it accepted when you
don't concat?

With the "...", there's nothing wrong with it. Without the
"...", as the results of ##, it's not a single token, so
undefined behavior results.
Comeau also gobbles it up even in strict, no-extensions mode.

It used to be a traditional solution; preprocessors generally
substitute (and concatenate) text strings, not tokens. I think
g++ introduced the check (it worked with older versions of gcc)
just to piss people off. Formally, it's undefined behavior: the
C committee wanted to allow preprocessors to work at the token
level. But in practice, no preprocessor has ever done this, and
your example had always worked, everywhere. Until gcc decided
to break it.

As Alf pointed out, it's a pain when it comes to generating
include paths. (In my own code, I use things like:
#include GB_dependentInclude(syst,"someFile.h")
to pick up an include which depends on the system, for example.
And there's a fair amount of token pasting going on in
GB_dependentInclude. Except that I don't token paste;
I concatenate string literals. Which shouldn't work, if you
read the standard literally, but in fact does, at least with all
of the compilers I've encountered.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,076
Latest member
OrderKetoBeez

Latest Threads

Top