2010-02-03 57 views
7

我正在一个项目中,我有许多由串联(数字等)形成的常量字符串。如何使用C预处理器将连接字符串转换为宽字符?

例如,我有一个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 Express的),我得到一个错误:

error: Concatenating wide "file.cpp" with narrow "(" 

我明白L前缀被添加只在我的表情中的第一项。我也试过这样:

#define _WIDEN(x) L ## #x 

其中“作品”,但给人的字符串L"\"file.cpp\" \"(\" \"42\" \")\""这显然不是很方便(而不是我所期待的),尤其是考虑到相对于其他这个宏很简单宏。

所以,我的问题是:我怎样才能得到它适用于MSVC++中的整个表达式,所以我可以得到与GCC相同的结果?我宁愿不创建第二个具有全范围标记的字符串,因为我必须为每个标记维护两个宏,这不是很方便,并且可能导致错误。另外,我还需要每个字符串的窄版本,因此不幸的是,使用全宽字符串也不是一种选择。

回答

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) 

应在两个海湾合作委员会和Visual C工作(至少,它为我工作,使用Visual C 2005)。

备注:您不应该定义名称以下划线开头的宏。这些名称是保留的,所以通过使用它们,您可以与系统头文件或将来版本的编译器中使用的某些名称冲突。而不是_WIDEN,请使用WIDEN_

+0

这很有效,虽然它是一种尴尬的语法,并且有很多开销......但它确实有效,并且我不必维护多个宏。 希望微软会更新它的预处理器来支持更多的C99功能,事情会更简单。 谢谢! – 2010-02-03 15:44:25

1

要连接两个宽文字字符串你可以使用

L"wide_a" L"wide_b" 

所以,你可以定义

#define WLOCATION WIDEN(__FILE__) L"(" WIDEN(STR(__LINE__)) L")" 

(注:关于MSVC++未测试)

+1

这样做是可以的,但宏观只是众多的一个,我宁愿定义它们只有一次,而不必维护两个副本(广泛和狭隘),特别是如果我有一天编辑它们。虽然我不得不承认,这可能很容易成为一种痛苦要维持! – 2010-02-03 14:20:23

0

只是使用空宽字符串文字应工作:

#define WLOCATION L"" __FILE__ "(" STR(__LINE__) ")" 
相关问题