如何从Windows路径的-D编译器定义变量创建字符串字面值

7
在Windows下,我有一个包含Windows风格路径的环境变量。我想将该路径构建到我的程序中并打印出来。例如,如果我的路径是c:\top,我使用-DTOP=$(TOP)将其传递给编译器。请注意,在将其传递给编译器之前,我无法将其转换为c:\\top。
目前,我有以下等效内容:
#define TOP=c:\top

我希望得到以下等效内容:

char path[]="c:\\top";

我不能只使用字符串操作符:

#define WRAP1(X) #X
#define WRAP(X) WRAP1(X)
char path[] = WRAP(TOP);

这只会得到字符串“c:\top”,编译器将其视为转义序列(即 \t)。

我认为可能的解决方案是构造一个字符串字面量,但其他解决方案也可以。是否有一种使用宏来构造字符串字面量的方法,可以产生以下结果:

char path[] = R"foo(c:\top)foo";

到目前为止,我的所有尝试都失败了,原因涉及到“或者()或者\”的变化。谢谢。

1
为什么?请注意,我在将其传递给编译器之前无法将其转换为c:\top。 - Eugene Sh.
我处于一个自定义编译环境中,无法更改。当我指定-D时,我不能使用额外的引号。编译环境还使用引号来解析传递给编译器的其他参数。 - shol74
1
你试过用正斜杠代替反斜杠吗? - Dmitri
3
正确的答案是通知构建环境的相关人员/团队需要进行更改。不要害怕“做不到”的情况,而应在出现问题时予以修复,例如无法引用任何内容或无法更改命令行中的任何内容等。这太疯狂了! - Brian Sidebotham
无法在命令行上更改任何内容?嗯,从安全角度来看,我可以理解,但如果这真的很重要,那么 Windows 可能不会像这样使用(显然它并不是为了这种安全灵活性而设计的)。无论如何,我会按照 @BrianSidebotham 在他的评论中建议的那样去做。 - user539810
显示剩余3条评论
2个回答

2

您可以使用字符串化运算符#将定义的路径转换为字符串。但是,这只适用于宏。实际上,您需要一个双重宏才能使其正常工作,否则它只会打印TOP。此外,将路径名放在引号中非常重要 - 示例中将路径存储在env PathDirName下。

为编译器定义路径 -

/DTOP="\"$(PathDirName)\\""

在代码中使用

#define STRINGIZE2(x) #x
#define STRINGIZE(x) STRINGIZE2(x)

char path[] = STRINGIZE(TOP);

这对我很有用。你已经接近成功了,希望这可以帮到你。
[编辑] 我现在可以看到问题所在 - 在C:\top中,它将'反斜杠t'视为控制代码'\t'。这种方法正在成为一种让人头痛的工作方式 - 因为你真的需要使用两个斜杠或正斜杠来创建文件名。我感觉自己在回答之前没有完全审查发生的事情而混淆了问题。
我尝试了几种方法,但由于无法更改传递的定义,我只能建议使用正则表达式库或手动扫描字符串 - 用正确的 '\' 字符替换控制字符。
我编写了一个示例,仅在你的示例中使用'\t',它不是很好的代码,它是为了解释正在做什么而编写的,希望它提供了一个可视化的例子,并且以(不太好的方式)解决了你在'C:\top'方面遇到的唯一问题。如我所说 - 如果使用这种方法,你将需要处理所有控制代码。 :-)
char stringName[256];
char* pRefStr = STRING(TOP);
char* pDestStr = stringName;
int nStrLen = strlen( pRefStr );

for( int nIndex = 0; nIndex < nStrLen; nIndex++ )
{
    if ( *pRefStr == '\t' )
    {
        *pDestStr++ = '\\';
        *pDestStr++ = 't';
        pRefStr++;
    }
    else
    {
        *pDestStr++ = *pRefStr++;
    }
}
*pDestStr = '\0';

再次道歉,如果有任何混淆之处 - 我已将我的答案留在这里供您参考 - 希望有人能想出一种处理定义字符串(带控制字符)的方法。

谢谢,尼尔


谢谢,但我无法更改传递的内容。我想知道是否可以使用连接字符串运算符##来构造字符串文字。 - shol74
嗯,由于它是一个宏,你可以尝试在TOP之前和之后添加引号。我无法尝试,因为我离开了我的开发机器 - 所以它应该可以工作。一种方法是使用format(..) - 如果我靠近我的机器,我会尝试这个。 - Neil
我已经编辑了我的回答shol74,不是好消息,因为我无法弄清楚如何在获取TOP定义时避免获得'\t'字符。正如我所提到的 - 希望有人能够解决这个问题。我认真尝试更改传递的定义。 - Neil
谢谢Neil。我的实际问题稍微严重一些。C:\top实际上是为了我的示例而缩短的。\t至少可以编译。我的实际路径中有一个\o,这是不行的。所以不幸的是,这也不仅仅是一个字符串替换的问题。还是感谢您的时间。 - shol74

0

你要寻找的相当奇特的语法可以在变量扩展中进行即时子字符串替换,以及一些引号转义来使定义成为字符串。我在这里找到了有关子字符串替换的信息here

set DIR=C:\WINDOWS获取已设置的环境变量,然后我们有一个测试程序:

#include <stdio.h>

#define STR(x)    #x
#define STRING(x) STR(x)      

int main( int argc, char* argv[] )
{
    printf( "DIR: %s\n", STRING(DIR) );
    return 0;
}

由于您无法在 shell 中引用,因此您可以在此处进行字符串化,但仍必须执行变量子字符串替换。

通过 cmd.exe 传递 env 变量:

gcc -Wall -DDIR=%DIR:\=\\% main.c

请查看上面的链接获取更多信息,或者谷歌子字符串替换。我找不到任何有关该函数的微软信息的链接(真是个惊喜!)。

由于已经使用引号字符的自定义构建环境,我无法在传递字符串之前更改它。因此,在那里添加任何引号字符只会提前终止我的字符串。我需要在.cpp文件中使用#define top c:\ top。 - shol74
@shol74 我已经编辑过了,将编译命令行中的引号删除了。这似乎是一个奇怪的要求。正如Neil所指出的那样,您可以使用宏扩展来将其转换为字符串。 - Brian Sidebotham
@shol74 我认为你的要求是不可能实现的,因为没有合理的编码可以供预处理器使用,而预处理器是你唯一拥有的工具。 - David Schwartz
是的,我只有预处理器。这就是为什么我希望能有一些聪明的方法将R"(c:\top)"连接起来并使其成为字符串字面量。 - shol74

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接