在VC++ 2003中,我可以将源文件保存为UTF-8,并且所有字符串都按原样使用.换句话说,以下代码将按字符串打印到控制台.如果源文件保存为UTF-8,则输出将为UTF-8.
printf("Chinese (Traditional)"); printf("??? (??)"); printf("??? (??)"); printf("Chinês (Tradicional)");
我已经使用UTF-8 BOM保存了UTF-8格式的文件.但是使用VC2008进行编译会导致:
warning C4566: character represented by universal-character-name '\uC911' cannot be represented in the current code page (932) warning C4566: character represented by universal-character-name '\uAD6D' cannot be represented in the current code page (932) etc.
导致这些警告的字符已损坏.适合语言环境的语言(在本例中为932 =日语)将转换为语言环境编码,即Shift-JIS.
我找不到让VC++ 2008为我编译的方法.请注意,我在源文件中使用的区域设置无关紧要.似乎没有一个语言环境说"我知道我在做什么,所以不要f $%## ng更改我的字符串文字".特别是,无用的UTF-8伪语言环境不起作用.
#pragma setlocale(".65001") => error C2175: '.65001' : invalid locale
"C"也不是:
#pragma setlocale("C") => see warnings above (in particular locale is still 932)
似乎VC2008强制所有字符进入指定的(或默认)语言环境,并且该语言环境不能是UTF-8.我不想更改文件以使用转义字符串,如"\ xbf\x11 ...",因为相同的源代码是使用gcc编译的,可以很好地处理UTF-8文件.
有没有办法指定源文件的编译应该保持字符串文字不变?
换句话说,在编译源文件时,我可以使用哪些编译标志来指定与VC2003的向后兼容性.即不要改变字符串文字,按字节顺序使用它们.
更新
感谢您的建议,但我想避免使用wchar.由于这个应用程序专门处理UTF-8中的字符串,因此使用wchar会要求我将所有字符串转换回UTF-8,这应该是不必要的.所有输入,输出和内部处理均采用UTF-8格式.这是一个简单的应用程序,在Linux和使用VC2003编译时工作正常.我希望能够使用VC2008编译相同的应用程序并使其工作.
为此,我需要VC2008不要尝试将其转换为本地机器的语言环境(日语,932).我希望VC2008向后兼容VC2003.我想要一个区域设置或编译器设置,表明字符串按原样使用,基本上是不透明的char数组或UTF-8.看起来我可能会被VC2003和gcc困住,但VC2008在这个例子中试图太聪明了.
更新:
我已经确定没有保证可以做到这一点.我在下面介绍的解决方案适用于英文版VC2003,但在使用日文版VC2003(或者可能是日文操作系统)进行编译时失败.无论如何,它不能依赖于工作.请注意,即使将所有内容声明为L""字符串也不起作用(并且如下所述在gcc中很痛苦).
相反,我相信你只需要咬住子弹并将所有文本移动到数据文件中并从那里加载它.我现在通过SimpleIni(跨平台的INI文件库)存储和访问INI文件中的文本.至少可以保证它的工作原理是所有文本都不在程序之内.
原版的:
我自己回答这个问题,因为只有Evan才明白这个问题.关于Unicode是什么以及如何使用wchar_t的答案与此问题无关,因为这不是关于国际化,也不是对Unicode,字符编码的误解.我感谢您尝试提供帮助,但如果我不够清楚,我会道歉.
问题是我有源文件需要在各种平台和编译器下进行交叉编译.该程序执行UTF-8处理.它不关心任何其他编码.我想在UTF-8中使用字符串文字,就像目前使用gcc和vc2003一样.我如何用VC2008做到这一点?(即向后兼容的解决方案).
这是我发现的:
gcc(v4.3.2 20081105):
字符串文字按原样使用(原始字符串)
支持UTF-8编码的源文件
源文件不得包含UTF-8 BOM
VC2003:
字符串文字按原样使用(原始字符串)
支持UTF-8编码的源文件
源文件可能有也可能没有UTF-8 BOM(没关系)
VC2005 +:
字符串文字由编译器按摩(没有原始字符串)
char字符串文字被重新编码为指定的语言环境
不支持UTF-8作为目标语言环境
源文件必须具有UTF-8 BOM
因此,简单的答案是,为了这个特殊目的,VC2005 +被破坏,并且不提供向后兼容的编译路径.将Unicode字符串输入编译程序的唯一方法是通过UTF-8 + BOM + wchar,这意味着我需要在使用时将所有字符串转换回UTF-8.
没有任何简单的跨平台方法将wchar转换为UTF-8,例如,wchar的大小和编码是什么?在Windows上,UTF-16.在其他平台上?它有所不同.有关详细信息,请参阅ICU项目.
最后我决定在vc2005 +以外的所有编译器上避免转换成本,如下所示.
#if defined(_MSC_VER) && _MSC_VER > 1310 // Visual C++ 2005 and later require the source files in UTF-8, and all strings // to be encoded as wchar_t otherwise the strings will be converted into the // local multibyte encoding and cause errors. To use a wchar_t as UTF-8, these // strings then need to be convert back to UTF-8. This function is just a rough // example of how to do this. # define utf8(str) ConvertToUTF8(L##str) const char * ConvertToUTF8(const wchar_t * pStr) { static char szBuf[1024]; WideCharToMultiByte(CP_UTF8, 0, pStr, -1, szBuf, sizeof(szBuf), NULL, NULL); return szBuf; } #else // Visual C++ 2003 and gcc will use the string literals as is, so the files // should be saved as UTF-8. gcc requires the files to not have a UTF-8 BOM. # define utf8(str) str #endif
请注意,此代码只是一个简化示例.生产使用需要以各种方式进行清理(线程安全,错误检查,缓冲区大小检查等).
这与以下代码一样使用.它在我对gcc,vc2003和vc2008的测试中干净地编译并正常工作:
std::string mText; mText = utf8("Chinese (Traditional)"); mText = utf8("??? (??)"); mText = utf8("??? (??)"); mText = utf8("Chinês (Tradicional)");
Brofield,
我遇到了完全相同的问题,只是偶然发现了一个不需要将源字符串转换为宽字符并返回的解决方案:将源文件保存为UTF-8 而不签名,VC2008将不管它.当我想出丢掉签名时工作得很好.总结一下:
Unicode(没有签名的UTF-8) - 代码页65001,不会在VC2008中抛出c4566警告并且不会导致VC混乱编码,而代码页65001(带签名的UTF-8)会抛出c4566(因为你有找到).
希望现在为您提供帮助,但它可能会加快您的VC2008应用程序以取消您的解决方法.
虽然使用宽字符串然后根据需要转换为UTF-8可能更好.我认为你最好的选择是如你所提到的那样在字符串中使用十六进制转义符.就像假设你想要代码点一样\uC911
,你可以这样做.
const char *str = "\xEC\xA4\x91";
我相信这会很好用,只是不太可读,所以如果你这样做,请评论它解释.
文件/高级保存选项/编码:"Unicode(UTF-8 无签名) - 代码页65001"
Visual C++(2005+)源文件的COMPILER标准行为是:
CP1252(本例中为西欧代码页):
"Ä"
→ C4 00
'Ä'
→ C4
L"Ä"
→ 00C4 0000
L'Ä'
→ 00C4
没有BOM的UTF-8:
"Ä"
→ C3 84 00
(= UTF-8)
'Ä'
→警告:多字符常量
"?"
→ E2 84 A6 00
(= UTF-8,如预期的那样)
L"A"
→ 00C3 0084 0000
(错!)
L'Ä'
→警告:多字符常量
L"?"
→ 00E2 0084 00A6 0000
(错!)
带BOM的UTF-8:
"Ä"
→ C4 00
(= CP1252,不再是UTF-8),
'Ä'
→ C4
"?"
→错误:无法转换为CP1252!
L"Ä"
→ 00C4 0000
(正确)
L'Ä'
→ 00C4
L"?"
→ 2126 0000
(正确)
你看,C编译器处理没有BOM的UTF-8文件的方式与CP1252相同.因此,编译器不可能将UTF-8和UTF-16字符串混合到编译输出中!所以你必须决定一个源代码文件:
要么使用UTF-8与BOM和生成UTF-16字符串仅(即总是使用L
前缀),
或没有BOM的UTF-8并且仅生成UTF-8字符串(即从不使用L
前缀).
不涉及7位ASCII字符,可以使用或不使用L
前缀
独立地,EDITOR可以自动检测没有BOM的UTF-8文件作为UTF-8文件.
从评论到这个非常好的博客
"使用UTF-8作为C和C++中使用Visual Studio的字符串的内部表示"
=> http://www.nubaria.com/en/blog/?p=289
#pragma execution_character_set("utf-8")
它需要Visual Studio 2008 SP1和以下修补程序:
http://support.microsoft.com/kb/980263 ....