c++ - 如何使用尾随反斜杠对字符串进行字符串化
问题描述
当我构建我的 C++ 项目时,编译器会生成这个等效的宏:
#define SOLUTION_DIR "c:\dev\my_project\"
在通常的#defined 宏中,尾随转义的双引号会由于未终止的字符串而触发编译器错误,但编译器可以做任何它想做的事情,并且即使字符串无效,它也可以按字面意思提供给代码。
将宏值扩展为 C 字符串的常用方法:
#define STRINGIZE( x ) #x
#define EXPAND( x ) STRINGIZE( x )
由于作为参数传递的未终止字符串,在这种情况下不起作用。
std::string s = EXPAND( SOLUTION_DIR );
...
error: newline in constant
有没有办法提取这个宏的字符串值并在我的代码中使用它相当于:
std::string str = R"(c:\dev\my_project\)";
其中 R 是此处描述的原始字符前缀https://en.cppreference.com/w/cpp/language/string_literal
笔记:
- 我尝试使用 R 前缀重写这些宏以避免转义最后的引号,但无法获得功能版本。
- 我可以告诉编译器在没有引号的情况下定义 SOLUTION_DIR 字符串,但我无法避免尾随反斜杠。但是,在这种情况下,由于未知的转义序列 (\d) 以及尾随反斜杠表示宏在下一行继续的事实,我会收到其他警告和错误。
更新: 这里是那些认为某些东西坏了需要修复的人的背景。
我使用 Visual Studio 2019 (VS)。在项目属性“C++/Preprocessor/Preprocessor Definitions”中可以定义各种宏,格式如下:
NAME1=VALUE1;NAME2=VALUE2;...
然后在编译时作为
#define NAME1 VALUE1
#define NAME2 VALUE2
VS 为各种目录和其他值(调试/发布、32 位或 64 位等)生成许多预定义的宏(不是 C++,而是构建环境宏)。它们采用 $(Name) 形式并设置为一些字符串值,例如:
$(Configuration) Debug
$(SolutionDir) C:\dev\some_project\
它们用于创建与位置无关的项目设置,例如临时或二进制输出目录,或为正在构建的项目的任何版本(例如 Debug/x64)设置正确的环境。
在我的情况下,我需要直接在我的代码中获取当前的解决方案路径,并且使用 $(SolutionDir) VS 宏似乎是最简单的方法。
所以这就是我在“属性/预处理器/预处理器定义”中定义我的 SOLUTION_PATH 宏的方式:
SOLUTION_DIR="$(SolutionDir)
它转化为最初描述的编译时宏:
#define SOLUTION_DIR "c:\dev\my_project\"
但是,默认情况下,许多扩展为路径的宏,包括 $(SolutionDir),都包含一个无法删除的尾随反斜杠,因此上面的“损坏”宏。
通常可执行二进制文件不需要也不应该知道任何关于其构建目录的信息,因此与路径相关的宏不一定设计用于定义 C++ 宏,尾随反斜杠不是问题。但是我的项目需要这些信息,因为它本身会触发其他依赖于当前环境的构建操作。
所以这不是任何组件的故障,一切都按设计工作,只是碰巧对于我的特定项目,能够以这种方式做事非常有用,即使它是非标准的。
解决方案
我能够通过添加尾随“。”来完成这项工作:
SOLUTION_DIR="$(SolutionDir)."
结果是等价的:
#define SOLUTION_DIR "C:\dev\my_project\."
它指向同一个目录,现在编译没有错误。
推荐阅读
- python - 如何将元组列表转换为字典
- c# - Visual Studio For Mac 编译错误
- php - wordpress 分页类别 404 在第 2 页
- mysql - 可以在不重组表的情况下优化此查询吗?
- r - R:在另一个向量中查找向量的索引(如果存在)
- c# - 'Activity1.OnNewIntent(Content.Intent)':找不到合适的方法来覆盖
- javascript - If - Else 都为真
- arrays - 试图弄清楚如何将组织切换到 Angular 组件中的基础
- node.js - JWT 获取用户详细信息并设置过期时间
- corda - Corda:我们可以开发由 IIS 网络服务器运行的 Dapp 来与 Corda 平台对话吗?