使用宏构建#include指令的路径 [英] Construct path for #include directive with macro

查看:451
本文介绍了使用宏构建#include指令的路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为我的程序的目标配置相关部分包含由宏动态创建的文件路径。



例如,我想构造一个将被调用的宏,如下所示:

  #include TARGET_PATH_OF(header.h)

这将扩展为这样的:

  #includecorefoundation / header.h

case)for OSX



到目前为止,所有尝试都失败了。



不起作用的例子:

  #include< iostream> 
#include< boost / preprocessor.hpp>

#define Dir目录/
#define文件filename.h

#define MakePath(f)BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
#define MyPath MakePath(File)

using namespace std;

int main(){
//这是一个测试 - 是的,我知道我可以在这里连接字符串
//但不是这样的情况#include
cout<< MyPath<< endl;
}

错误:

  ./enableif.cpp:31:13:error:pasting formed'/ filename',无效的预处理令牌
cout< MyPath<< endl;
^
./enableif.cpp:26:16:note:从宏'MyPath'扩展
#define MyPath MakePath(File)
^
./enableif .cpp:25:40:注意:从'MakePath'宏扩展
#define MakePath(f)BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
^
/ usr / local / include / boost / preprocessor / cat.hpp:22:32:注意:从宏BOOST_PP_CAT扩展
#define BOOST_PP_CAT(a,b)BOOST_PP_CAT_I(a,b)
^
/ usr /本地/ include / boost / preprocessor / cat.hpp:29:36:注意:从宏'BOOST_PP_CAT_I'扩展
#define BOOST_PP_CAT_I(a,b)a ## b
^
1错误生成。


解决方案

我倾向于同意 utnapistim的回答你不应该这样做,即使你可以。但是,事实上,你可以,至少有一些C编译器。 [注1]



有两个问题需要克服。第一个是你不能使用 ## 运算符来创建不是有效的预处理器令牌的东西,并且路径名不能作为有效的预处理器令牌,因为它们包括 / 字符。 (如果令牌以数字开头,则会正常,但 / 将永远不会工作。)



您实际上不需要连接标记,以便用运算符将它们进行字符串化,因为该运算符将整个宏参数进行字符串化,并且参数可以由多个令牌。但是,stringify尊重空格[Note 2],因此 STRINGIFY(Dir File)将无法工作;它会导致directory / filename.h,并且文件名中的额外空间将导致 #include 失败。因此,您需要连接不含任何空格的 Dir 文件



下面通过使用类似函数的宏来返回其参数来解决第二个问题:

  #define IDENT x)x 
#define XSTR(x)#x
#define STR(x)XSTR(x)
#define PATH(x,y) ))

#define Dir sys /
#define文件socket.h

#include PATH(Dir,File)

请注意,调用 PATH 中的空格字符将被保留。因此 Path(Dir,File)将失败。



当然,你不需要复杂的 IDENT 宏,如果您可以写入没有空格的连接。例如:

  #define XSTR(x)#x 
#define STR(x)XSTR b
$ b #define Dir sys
#define文件socket.h

#include STR(Dir / File)
pre>




注意




  1. 我尝试使用clang,gcc和icc,如 godbolt 上提供。我不知道它是否与Visual Studio一起使用。


  2. 更准确地说,它半符合空格:空格被转换为单个空格字符。 p>



I would like to have include file paths dynamically created by a macro for a target-configuration-dependent part of my program.

for example, I would like to construct a macro that would be invoked like this:

#include TARGET_PATH_OF(header.h)

Which will expand to a something like this:

#include "corefoundation/header.h"

when the source is configured (in this case) for OSX

So far all attempts have failed. I'm hoping someone out there has done this before?

example of what does not work:

#include <iostream>
#include <boost/preprocessor.hpp>

#define Dir directory/
#define File filename.h

#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
#define MyPath MakePath(File)

using namespace std;

int main() {
    // this is a test - yes I know I could just concatenate strings here
    // but that is not the case for #include
    cout << MyPath << endl;
}

errors:

./enableif.cpp:31:13: error: pasting formed '/filename', an invalid preprocessing token
    cout << MyPath << endl;
            ^
./enableif.cpp:26:16: note: expanded from macro 'MyPath'
#define MyPath MakePath(File)
               ^
./enableif.cpp:25:40: note: expanded from macro 'MakePath'
#define MakePath(f) BOOST_PP_STRINGIZE(BOOST_PP_CAT(Dir,f))
                                       ^
/usr/local/include/boost/preprocessor/cat.hpp:22:32: note: expanded from macro 'BOOST_PP_CAT'
#    define BOOST_PP_CAT(a, b) BOOST_PP_CAT_I(a, b)
                               ^
/usr/local/include/boost/preprocessor/cat.hpp:29:36: note: expanded from macro 'BOOST_PP_CAT_I'
#    define BOOST_PP_CAT_I(a, b) a ## b
                                   ^
1 error generated.

解决方案

I tend to agree with the comment in utnapistim's answer that you shouldn't do this even though you can. But, in fact, you can, at least with some C compilers. [Note 1]

There are two issues to overcome. The first one is that you cannot use the ## operator to create something which is not a valid preprocessor token, and pathnames do not qualify as valid preprocessor tokens because they include / and . characters. (The . would be ok if the token started with a digit, but the / will never work.)

You don't actually need to concatenate tokens in order to stringify them with the # operator, since that operator will stringify an entire macro argument, and the argument may consist of multiple tokens. However, stringify respects whitespace [Note 2], so STRINGIFY(Dir File) won't work; it will result in "directory/ filename.h" and the extraneous space in the filename will cause the #include to fail. So you need to concate Dir and File without any whitespace.

The following solves the second problem by using a function-like macro which just returns its argument:

#define IDENT(x) x
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define PATH(x,y) STR(IDENT(x)IDENT(y))

#define Dir sys/
#define File socket.h

#include PATH(Dir,File)

Note that a whitespace character in the call to PATH will be preserved. So Path(Dir, File) will fail.

Of course, you wouldn't need the complication of the IDENT macro if you could write the concatenation without spaces. For example:

#define XSTR(x) #x
#define STR(x) XSTR(x)

#define Dir sys
#define File socket.h

#include STR(Dir/File)


Notes

  1. I tried it with clang, gcc and icc, as available on godbolt. I don't know if it works with Visual Studio.

  2. More accurately, it semi-respects whitespace: whitespace is converted to a single space character.

这篇关于使用宏构建#include指令的路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆