Mar*_*ine 7 c++ wchar-t stringification visual-c++ c-preprocessor
我正在进行一个项目,我有许多由连接(数字等)形成的常量字符串.
例如,我有一个LOCATION格式化的宏,__FILE__并且__LINE__在打印消息或错误时,我可以用它来知道我在代码中的位置:
#define _STR(x) # x
#define STR(x) _STR(x)
#define LOCATION __FILE__ "(" STR(__LINE__) ")"
Run Code Online (Sandbox Code Playgroud)
因此,这将格式化像"file.cpp(42)"的位置.问题是当我尝试将结果转换为宽字符串时:
#define _WIDEN(x) L ## x
#define WIDEN(x) _WIDEN(x)
#define WLOCATION WIDEN(LOCATION)
Run Code Online (Sandbox Code Playgroud)
这适用于GCC,并导致L"file.cpp(42)"插入到我的代码中.但是,当使用MSVC++(使用Visual C++ 2008 Express)尝试此操作时,我收到一个错误:
error: Concatenating wide "file.cpp" with narrow "("
Run Code Online (Sandbox Code Playgroud)
我知道L前缀只会添加到我的表达式的第一个术语中.我也试过这个:
#define _WIDEN(x) L ## #x
Run Code Online (Sandbox Code Playgroud)
哪个"有用",但是给出了L"\"file.cpp\" \"(\" \"42\" \")\""显然不太方便的字符串(而不是我想要的),特别是考虑到这个宏与其他宏相比很简单.
所以,我的问题是:如何才能将它应用于MSVC++中的整个表达式,这样我可以得到与GCC相同的结果?我宁愿不用全宽标记创建第二个字符串,因为我必须为每个标记维护两个宏,这不是很方便并且可能导致错误.另外,我也需要每个字符串的窄版本,所以不幸的是,使用全宽字符串也不是一种选择.
Tho*_*nin 11
根据C标准(又名"ISO-9899:1999"又名"C99"),Visual C是错误的并且gcc是正确的.该标准规定,第6.4.5/4节:
在转换阶段6中,由任何相邻字符序列和宽字符串文字标记指定的多字节字符序列被连接成单个多字节字符序列.如果任何标记是宽字符串文字标记,则生成的多字节字符序列将被视为宽字符串文字; 否则,它被视为字符串文字.
所以你可以投诉.可以说,C标准的先前版本(又名"C89"又名"C90"又名"ANSI C")没有要求将宽字符串与非宽字符串合并.虽然C99现在已有十多年的历史,但似乎微软并没有兴趣使其C编译器符合要求.一些用户报告说,通过编译C代码可以访问一些"C99"功能,就好像它是C++代码一样,因为C++包含这些功能 - 而对于C++,Microsoft做了一些努力.但这似乎并没有扩展到预处理器.
在C89方言中,我认为你所寻找的是不可能的(实际上我很确定它,因为我已经编写了自己的预处理器,我想我知道我在说什么).但是你可以添加一个额外的参数并传播它:
#define W(x) W_(x)
#define W_(x) L ## x
#define N(x) x
#define STR(x, t) STR_(x, t)
#define STR_(x, t) t(#x)
#define LOCATION_(t) t(__FILE__) t("(") STR(__LINE__, t) t(")")
#define LOCATION LOCATION_(N)
#define WLOCATION LOCATION_(W)
Run Code Online (Sandbox Code Playgroud)
这应该适用于gcc和Visual C(至少,它适用于我,使用Visual C 2005).
附注:您不应该定义名称以下划线开头的宏.这些名称是保留的,因此通过使用它们,您可能会与系统标头或编译器的未来版本中使用的某些名称发生冲突.而不是_WIDEN,使用WIDEN_.