我正在做一个项目,在这个项目中,我有许多由连接(数字等)形成的常量字符串。
例如,我有一个LOCATION
宏,它将__FILE__
和__LINE__
格式化为一个字符串,在打印消息或错误时,我可以使用该字符串来了解我在代码中的位置:
#define _STR(x) # x
#define STR(x) _STR(x)
#define LOCATION __FILE__ "(" STR(__LINE__) ")"
因此,这将格式化一个类似于"file.cpp(42)“的位置。问题是当我尝试将结果转换为宽字符串时:
#define _WIDEN(x) L ## x
#define WIDEN(x) _WIDEN(x)
#define WLOCATION WIDEN(LOCATION)
这对于GCC来说工作得很好,结果是在我的代码中插入了L"file.cpp(42)“。但是,在使用MSVC++ (使用Visual C++ 2008学习版)尝试此操作时,我收到一个错误:
error: Concatenating wide "file.cpp" with narrow "("
我知道L
前缀只添加到我表达式中的第一项。我也尝试过这个:
#define _WIDEN(x) L ## #x
它“工作”,但给出了字符串L"\"file.cpp\" \"(\" \"42\" \")\""
,这显然不是很方便(也不是我想要的),特别是考虑到这个宏与其他宏相比很简单。
因此,我的问题是:如何将其应用于MSVC++中的整个表达式,以便我可以获得与使用GCC相同的结果?我不想创建第二个具有全宽标记的字符串,因为那样我就必须为每个标记维护两个宏,这不是很方便,而且可能会导致错误。另外,我还需要每个字符串的窄版本,所以不幸的是,使用全宽字符串也不是一种选择。
发布于 2010-02-03 23:08:02
根据C标准(又称"ISO-9899:1999“又称"C99"),Visual C是错误的,而gcc是正确的。该标准规定,第6.4.5/4节:
在转换阶段6中,由任何相邻字符序列和宽字符串文字标记指定的多字节字符序列被连接成单个多字节字符序列。如果有任何标记是宽字符串文字标记,则将生成的多字节字符序列视为宽字符串文字;否则,将其视为字符串文字。
这样你就可以投诉了。可以说,C标准的前一个版本(又称"C89“又名"C90”又名"ANSI“)并不强制将宽字符串与非宽字符串合并。虽然C99现在已经有十多年的历史了,但微软似乎对让它的C编译器符合标准没有兴趣。一些用户报告说,能够通过编译C代码来访问一些"C99“特性,就像它是C++代码一样,因为C++包括这些特性--微软为C++做出了努力。但这似乎并没有扩展到预处理器。
在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)
它应该可以在gcc和Visual C上工作(至少,它在我使用Visual C 2005的情况下可以工作)。
附注:您不应该定义名称以下划线开头的宏。这些名称是保留的,因此使用它们可能会与系统标头或编译器未来版本中使用的一些名称发生冲突。使用WIDEN_
而不是_WIDEN
。
发布于 2010-02-03 22:09:29
要连接两个宽文字字符串,您可以使用
L"wide_a" L"wide_b"
所以你可以定义
#define WLOCATION WIDEN(__FILE__) L"(" WIDEN(STR(__LINE__)) L")"
(注意:未在MSVC++上测试)
发布于 2014-03-03 06:24:14
只要使用一个空的宽字符串就可以了:
#define WLOCATION L"" __FILE__ "(" STR(__LINE__) ")"
https://stackoverflow.com/questions/2192416
复制相似问题