如何将Visual Studio宏值转换为预处理器指令?

Luk*_*sen 10 c c++ visual-studio

在我的项目中,我需要$(SolutionDir)在运行时访问宏的值.为此,我尝试添加类似DEBUG_ROOT=$(SolutionDir)或之前的预处理器条目,DEBUG_ROOT=\"$(SolutionDir)\"但由于$(SolutionDir)包含单个\字符(例如$(SolutionDir) = c:\users\lukas\desktop\sandbox\),因此由于无效的转义序列而导致各种编译器错误.

有没有一种简单的方法可以将$(SolutionDir)宏的值传递给我的代码?

底色

OutputDebugString(..)在我的调试版本中使用了很多函数来查看我的代码在做什么.

/* debug.h */
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define LOCATION __FILE__ "(" TOSTRING(__LINE__) ") : "

#if !defined(DEBUG_ROOT)
#define DEBUG_ROOT    "#"   /* escape string to force strstr(..) to fail */
#endif

/*
**  DBGMSG macro setting up and writing a debug string.
**  Note: copying the strings together is faster than calling OutputDebugString(..) several times!
**  Todo: Ensure that size of dbgStr is not exceeded!!!
*/
#define DBGMSG(text) \
    { \
        char dbgStr[1024]; \
        char *pFile; \
        pFile = strstr(LOCATION, DEBUG_ROOT); \
        if (pFile == LOCATION) \
        { \
            wsprintf(dbgStr, ".%s", pFile + strlen(DEBUG_ROOT)); \
        } \
        else \
        { \
            wsprintf(dbgStr, "%s", LOCATION); \
        } \
        wsprintf(dbgStr, "%s%s", dbgStr, text); \
        OutputDebugString(dbgStr); \
    }


/* somewhere in the code */
DBGMSG("test")
Run Code Online (Sandbox Code Playgroud)

使用剪切将导致类似于c:\users\lukas\desktop\sandbox\testconsole\main.c(17) : testVisual Studio的输出窗口中的打印输出.这样可以加快查找代码中导致打印输出的位置,因为您只需双击输出窗口的行,Visual Studio就会自动跳转到指定的代码位置.

由于取决于解决方案的位置,绝对路径(__FILE__扩展到绝对路径)调试字符串的"标题"可能会变得非常长.我已经看到Visual Studio足够聪明,可以理解解决方案根目录的相对路径.为了减少字符串的长度,我正在检查是否__FILE__在一个DEBUG_ROOT目录中,如果是,我DEBUG_ROOT用一个简单的替换'.'来生成相对路径DEBUG_ROOT.所以,如果我写#define DEBUG_ROOT "c:\\users\\lukas\\desktop\\sandbox"上面例子的最终调试字符串将是.\testconsole\main.c(17) : test.目前我正在设置DEBUG_ROOT项目预处理器定义中的值.

由于有几个人正在开展项目,因此在项目设置中拥有绝对路径并不是一个聪明的举动,因为每个团队成员可能会将源文件签出到不同的根目录.所以我试图使用$(SolutionDir)宏来创建类似的东西DEBUG_ROOT=\"$(SolutionDir)\\".但通过这样做,我遇到了麻烦.由于$(SolutionDir) = c:\users\lukas\desktop\sandbox\扩展DEBUG_ROOT导致未定义的转义序列,未终止的字符串和更多丑陋的编译器错误......

根据kfsone的答案,我提出了以下解决方案,它可以将Visual Studio宏的任何值传递$(SolutionDir)到您的代码中.以下解决方案独立于使用的Visual Studio版本和语言C/C++.

添加SOLUTION_DIR=\"$(SolutionDir)"到项目的预处理器条目会导致编译器命令行看起来像这样:

/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "SOLUTION_DIR=\"C:\Users\Lukas\Desktop\sandbox\""
/Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc80.pdb" /W3 /nologo /c /Wp64 /ZI /TP
/errorReport:prompt
Run Code Online (Sandbox Code Playgroud)

注意,$(SolutionDir)在a之前\"创建一个"chaeded的前面值,$(SolutionDir)但是由一个单独终止".查看编译器的命令行显示终止"是由最后一个转义\$(SolutionDir).

SOLUTION_DIR在代码中使用会导致未知的转义序列,并且字符串最终\会删除所有字符.这是由编译器完成的,编译器扩展SOLUTION_DIR\作为转义序列的开头进行解释.

使用TOSTRING(x)上面发布的代码的宏解决了这个问题,因为它强制编译器按原样使用字符串而无需进一步处理.

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)

#define SOLUTION_DIR2   TOSTRING(SOLUTION_DIR)

// the following line may cause compiler warnings (unrecognized character escape sequence)
printf("%s\n", SOLUTION_DIR);    // prints C:UsersLukasDesktopsandbox 

// the following line compiles without any warnings
printf("%s\n", SOLUTION_DIR2);   // prints "C:\Users\Lukas\Desktop\sandbox"
Run Code Online (Sandbox Code Playgroud)

从这里开始,只需要一个简单的步骤就可以删除"字符SOLUTION_DIR2.

kfs*_*one 12

有一个C++ 11功能,原始字符串文字,可在Visual Studio版本2013及更高版本中使用,它允许您执行此操作.语法是

'R"' <delimiter> '(' <string> ')' <delimiter> '"'
Run Code Online (Sandbox Code Playgroud)

例如,如果你选择"?:?" 作为你的分隔符

R"?:?(don't\escape)?:?"
Run Code Online (Sandbox Code Playgroud)

或者如果你选择"Foo123"

R"Foo123(don't\escape)Foo123"
Run Code Online (Sandbox Code Playgroud)

但是对于这个演示,我要去?作为单字符分隔符,因为我们知道它在Windows文件名中是非法的.

现在您可以设置项目级预处理器定义:

DIR=R"?(C:\\Temp\\)?"
Run Code Online (Sandbox Code Playgroud)

然后以下代码生成预期输出

#include <iostream>
int main() {
    std::cout << DIR << '\n';
}
Run Code Online (Sandbox Code Playgroud)

C:\\Temp\\
Run Code Online (Sandbox Code Playgroud)

代替

C:\Temp\
Run Code Online (Sandbox Code Playgroud)

现在要捕获SolutionDir宏,就像它一样简单

DIR=R"?($(SolutionDir))?"
Run Code Online (Sandbox Code Playgroud)

如果这很痛苦,您可以在属性表中添加自定义宏.转到"Property Explorer"并右键单击您的项目,添加一个新的属性表,将其称为"ProjectMacros.props"或其他内容.

展开项目并选择其中一个配置,例如debug,双击"PropertySheet"值打开"PropertySheet PropertyPages"并选择"UserMacros"

PropertySheet宏页面

点击"添加宏"

Name: RawSolutionDir
Value: R"?path?($(SolutionDir))?path?"
Run Code Online (Sandbox Code Playgroud)

您现在应该能够使用预处理器条目

SOLUTIONDIR=$(RawSolutionDir)
Run Code Online (Sandbox Code Playgroud)