Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
348 views
in Technique[技术] by (71.8m points)

c++ - Macro concatenation using compiler define

This should be simple, but I'm struggling to figure it out. I have PROJECT_NAME as a compiler (g++) -D define, and I want to concatenate it with some other text to form a namespace name. My current approach is this:

#define VERSION_NAMESPACE PROJECT_NAME ## Versioning

For my current project, I expect VERSION_NAMESPACE to be Syren_DLLVersioning. Instead I get a compiler error:

error: 'PROJECT_NAMEVersioning' has not been declared

But according to the g++ call, PROJECT_NAME is being defined properly:

ccache g++ ... -DPROJECT_NAME=Syren_DLL ...

Why is PROJECT_NAME not being replaced before the concatenation takes place?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A macro name is not expanded when it appears next to the ## operator, so you need more layers of indirection:

#define P_VERSION2(foo)   foo ## Versioning
#define P_VERSION(foo)    P_VERSION2(foo)
#define VERSION_NAMESPACE P_VERSION(PROJECT_NAME)

so that PROJECT_NAME is expanded as the argument of P_VERSION and then concatenated in P_VERSION2.

In section 16.3.3 [cpp.concat], paragraph 3, it is specified

For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.

that preprocessing tokens adjacent to a ## preprocessing token are concatenated before macro-replacement is done on the replacement list. Therefore, PROJECT_NAME must be passed through another (function-like) macro for it to be replaced and concatenated with Versioning.

But in 16.3.1 [cpp.subst], paragraph 1, the standard specifies (emphasis added by me)

After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

that macro parameters are not subject to further macro-expansion if adjacent to a ## preprocessing token. Therefore, the function-like macro that receives PROJECT_NAME as argument must not directly concatenate its argument with Versioning, but to expand PROJECT_NAME it must call another function-like macro that finally does the concatenation.

So in the above, with the invocation ccache g++ ... -DPROJECT_NAME=Syren_DLL ..., PROJECT_NAME is replaced with Syren_DLL when P_VERSION(PROJECT_NAME) is expanded, resulting in P_VERSION2(Syren_DLL) which then leads to the concatenation of Syren_DLL and Versioning.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...