gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 15:54:52 32 4
gpt4 key购买 nike

在我的项目中,我需要在运行时访问$(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")

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

由于根据解决方案的位置,绝对路径( __FILE__会扩展为绝对路径),因此调试字符串的“ header ”可能会变得很长。我已经看到Visual Studio足够聪明,可以理解例如的相对路径。解决方案的根目录。为了减少字符串的长度,我正在检查 __FILE__是否在 DEBUG_ROOT目录中,如果是,那么我将 DEBUG_ROOT替换为简单的 '.'以生成 DEBUG_ROOT的相对路径。因此,如果我编写 #define DEBUG_ROOT "c:\\users\\lukas\\desktop\\sandbox",则上面示例的最终调试字符串将为 .\testconsole\main.c(17) : test。目前,我正在项目的预处理程序定义中设置 DEBUG_ROOT的值。

由于有几个人在从事项目工作,因此在项目设置中具有绝对路径并不是明智的举动,因为每个团队成员都可以将源文件 check out 到不同的根目录中。因此,我尝试使用 $(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

请注意, $(SolutionDir)之前是 \",以创建 ",其特征是 $(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"

从这里开始,只需执行一些魔术操作即可从 "中删除 SOLUTION_DIR2字符,这只是一个简单的步骤。

最佳答案

Visual Studio 2013及更高版本中提供了C++ 11功能,即原始字符串文字,您可以通过此功能执行此操作。语法是

'R"' <delimiter> '(' <string> ')' <delimiter> '"'

例如如果您选择“?:?”作为您的分隔符
R"?:?(don't\escape)?:?"

或者,如果您选择“Foo123”
R"Foo123(don't\escape)Foo123"

但是对于这个演示,我要继续吗?作为单字符定界符,因为我们知道在Windows文件名中它是非法的。

现在,您可以设置项目级别的预处理器定义:
DIR=R"?(C:\\Temp\\)?"

然后以下代码生成预期的输出
#include <iostream>
int main() {
std::cout << DIR << '\n';
}


C:\\Temp\\

代替
C:\Temp\

现在要捕获SolutionDir宏,就像
DIR=R"?($(SolutionDir))?"

如果这很麻烦,则可以在属性表中添加一个自定义宏。转到“属性资源管理器”,右键单击您的项目,添加一个新的属性表,将其称为“ProjectMacros.props”或其他名称。

展开您的项目并选择一种配置,例如调试,双击“PropertySheet”值以打开“PropertySheet PropertyPages”并选择“UserMacros”

点击“添加宏”
Name: RawSolutionDir
Value: R"?path?($(SolutionDir))?path?"

您现在应该可以使用预处理程序条目
SOLUTIONDIR=$(RawSolutionDir)

关于c++ - 如何将Visual Studio宏值转换为预处理器指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30438911/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com