C++ 使用编译器定义的宏连接
这应该很简单,但我正在努力想办法。我有C++ 使用编译器定义的宏连接,c++,c,c-preprocessor,C++,C,C Preprocessor,这应该很简单,但我正在努力想办法。我有PROJECT\u NAME作为编译器(g++)-D定义,我想将它与其他一些文本连接起来,形成一个名称空间名称。我目前的做法是: #define VERSION_NAMESPACE PROJECT_NAME ## Versioning 对于我当前的项目,我希望VERSION\u NAMESPACE是Syren\u DLLVersioning。相反,我得到了一个编译器错误: error: 'PROJECT_NAMEVersioning' has not be
PROJECT\u NAME
作为编译器(g++
)-D
定义,我想将它与其他一些文本连接起来,形成一个名称空间名称。我目前的做法是:
#define VERSION_NAMESPACE PROJECT_NAME ## Versioning
对于我当前的项目,我希望VERSION\u NAMESPACE
是Syren\u DLLVersioning
。相反,我得到了一个编译器错误:
error: 'PROJECT_NAMEVersioning' has not been declared
但是根据g++
调用,PROJECT\u NAME
的定义是正确的:
ccache g++ ... -DPROJECT_NAME=Syren_DLL ...
为什么在连接发生之前,
PROJECT\u NAME
没有被替换?宏名称出现在#
操作符旁边时不会展开,因此需要更多的间接层:
#define P_VERSION2(foo) foo ## Versioning
#define P_VERSION(foo) P_VERSION2(foo)
#define VERSION_NAMESPACE P_VERSION(PROJECT_NAME)
因此,PROJECT\u NAME
被展开为p\u VERSION
的参数,然后连接到p\u VERSION2
中
在第16.3.3节[cpp.concat]第3段中,对其进行了规定
对于类对象宏调用和类函数宏调用,在重新检查替换列表以查找更多要替换的宏名称之前,将删除替换列表中的##
预处理标记的每个实例(而不是从参数中),并将前面的预处理标记与下面的预处理标记连接起来
在替换列表上执行宏替换之前,将连接与##
预处理标记相邻的预处理标记。因此,PROJECT\u NAME
必须通过另一个(类似函数的)宏来替换,并与版本控制
连接
但在16.3.1[cpp.subst]第1段中,本标准规定了(由我补充强调)
在确定调用函数(如宏)的参数后,将进行参数替换。替换列表中的参数,除非前面有一个#
或#
预处理标记,或者后面有一个#
预处理标记(请参见下文),否则在展开其中包含的所有宏后,将被相应的参数替换。在被替换之前,每个参数的预处理标记被完全宏替换,就好像它们构成了预处理文件的其余部分一样;没有其他预处理令牌可用
如果宏参数与##
预处理令牌相邻,则不会进行进一步的宏扩展。因此,接收PROJECT\u NAME
作为参数的函数类宏不能直接将其参数与Versioning
连接起来,但要展开PROJECT\u NAME
,它必须调用另一个函数类宏,最终进行连接
因此在上面,通过调用
ccache g++-DPROJECT\u NAME=Syren\u DLL…
,PROJECT\u NAME
在P\u VERSION(PROJECT\u NAME)
扩展时被替换为Syren\u DLL
,从而导致P\u VERSION2(Syren\u DLL)
连接Syren\u DLL
和VERSION
,我甚至不确定这是否严格合法(这可能是特定于编译器的行为)…你能在这方面找到标准吗?哎呀,我没有充分使用预处理器。原始版本缺少一层间接寻址。感谢你让我查找它。幸运的是,我放弃了并问了,我肯定不会猜到这一点。谢谢!