替换预处理器定义中的字符

时间:2017-08-16 07:09:53

标签: c++ c++11 macros

我有一个定义,其中包含一个路径(没有转义序列),如下所示:

// Incorrect
#define PATH "c:\blah\blah\file.cfg"

我更喜欢这样:

// Corrected
#define PATH "c:\\blah\\blah\\file.cfg"

虽然遗憾的是我无法修改宏定义(实际上是生成包含宏的源的脚本...),但添加前缀除外。现在我需要打开此路径中给出的文件。我尝试了这样的c ++ 11原始字符串文字:

// Modified definition
#define PATH R"c:\blah\blah\file.cfg"
std::ifstream(PATH); // error: unrecognised escape sequence 

现在的问题是如何使用宏替换所有\

备注(如果有关系):
编译:MSVC 14.0
操作系统:Windows 7

2 个答案:

答案 0 :(得分:2)

您生成的原始字符串的语法不正确。

这是正确的:

#define PATH R"(c:\blah\blah\file.cfg)"

检查CPP参考的(6)语法格式:

  

前缀(可选)R“分隔符(raw_characters)分隔符”(6)

请参阅:string literal

示例:http://ideone.com/OZggmK

答案 1 :(得分:2)

您可以使用预处理器的stringify-operator #,它不仅将参数封装在双引号中,还会转义字符串中的“普通”反斜杠。然后 - 在运行时 - 切断stringify引入的额外双引号。

所以这个想法如下:

  1. 以某种方式将PATH字符串化为"c:\blah\blah\file.cfg" "\"c:\\blah\\blah\\file.cfg\""。注意字符串本身 包含双引号作为第一个和最后一个字符。

  2. 在运行时,使用substr来减少(不需要的)之间的值 双引号

  3. 有点棘手的是将一个本身作为宏提供的值进行字符串化。为此,您可以使用具有可变参数的宏(因为它们会被扩展)。 所以完整的代码如下:

    #define PATH "c:\blah\blah\file.cfg"
    
    #define STRINGIFY_HELPER(A) #A
    #define STRINGIFY(...) STRINGIFY_HELPER(__VA_ARGS__)
    #define NORMALIZEPATH(P) string(STRINGIFY(P)).substr(1,strlen(STRINGIFY(P))-2)
    
    int main() {
    
        string filename =  NORMALIZEPATH(PATH);
        cout << "filename: " << filename << endl;
    
        return 0;
    }
    

    输出:

    filename: c:\blah\blah\file.cfg