在我的项目中,我需要访问的价值$(SolutionDir)
运行时的宏。为此,我尝试添加预处理器条目,例如DEBUG_ROOT=$(SolutionDir)
or 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")
使用截图会导致打印输出像c:\users\lukas\desktop\sandbox\testconsole\main.c(17) : test
在 Visual 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
导致未定义的转义序列、未终止的字符串和更多丑陋的编译器错误......
Solution
根据以下的回答kfsone https://stackoverflow.com/users/257645/kfsone我提出了以下解决方案,可以传递 Visual Studio 宏的任何值,例如$(SolutionDir)
到你的代码中。以下解决方案与所使用的 Visual Studio 版本和语言 C/C++ 无关。
Adding 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
注意$(SolutionDir)
前面有一个\"
创建一个"
值前面的字符$(SolutionDir)
但由单个终止"
。查看编译器的命令行显示终止"
被最后一个逃脱\
of $(SolutionDir)
.
Using 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"
从这里开始,只需执行一些字符串魔术即可删除"
字符来自SOLUTION_DIR2
.