如何创建字符串文字 UTF-8 在 Visual C++ 2008

在 VC++ 2003 我可以将源文件保存为 UTF-8, 所有这些线条都像它一样使用。 换句话说,以下代码将显示在控制台上的行。 如果源文件已保存为 UTF-8, 这出口将是 UTF-8.


printf/"Chinese /Traditional/"/;
printf/"中国語 /繁体/"/;
printf/"중국어 /번체/"/;
printf/"Chinês /Tradicional/"/;


我以格式保存了文件 UTF-8 从 UTF-8 BOM. 但是,汇编S. 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.


导致这些警告的符号损坏。 那些匹配的人 locale /在这种情况下 932 = 日本人/, 转变为编码 locale, IE Shift-JIS.

我找不到一种方法 VC++ 2008 为我编译它。 请注意,这无关紧要 locale 我在源文件中使用。 看起来不是 locale, 这说: "我知道我做了什么,所以不要改变我的字符串文字文字". 特别是无用的 UTF-8 伪区域设置不起作用。


#pragma setlocale/".65001"/ 
=> error C2175: '.65001' : invalid locale


就像我一样。 "C":


#pragma setlocale/"C"/ 
=> see warnings above /in particular locale is still 932/


看起来 VC2008 强制指定的所有字符 /或默认情况下/ locale, 所以呢 locale 不可能是 UTF-8. 我不想更改文件以使用逃生行类型 " \xbf\x11...", 因为使用相同的源代码使用 gcc, 这可能会处理文件 UTF-8.

有没有办法指定源文件的编译应该留下字符串文字完整?

要以不同的方式设置,我可以使用什么编译标志来指示向后兼容性 VC2003 在编译源文件时,即不要更改字符串文字,请使用它们的字节字节。

更新

谢谢你的建议,但我想避免 wchar. 由于此应用程序专门处理行 UTF-8, 使用 wchar 将要求我转回所有行 UTF-8, 应该是不必要的。 所有入口,输出和内部处理都在 UTF-8. 这是一个简单的应用程序,它很棒 Linux, 和在编译时 VC2003. 我希望能够编译相同的应用程序 VC2008 并使它起作用。

要做到这一点,我需要 VC2008 没有试图将它转换为 locale 我的本地车 /日本人, 932/. 我想要 VC2008 回来兼容 VC2003. 我需要一个参数 locale 或编译器表示行的使用,基本上像透明数阵列 char 或者怎么样 UTF-8. 似乎我可以陷入困境 VC2003 和 gcc, 虽然 VC2008 在这种情况下试图太聪明。
已邀请:

奔跑吧少年

赞同来自:

更新:

我决定没有保证方法。 我想象下面的决定为英文版。 VC2003, 但是在使用日语版本编译时失败 VC2003 /或者也许这是一个日本人 OS/. 无论如何,依靠他的工作是不可能的。 请注意,即使是像排的一切宣布 L"" 不工作 /和痛苦的B. gcc, 如下所述/.

相反,我相信您只需要咬紧子弹并将整个文本移动到数据文件并从那里下载。 现在我已经存储并获得了对文本的访问 INI 文件周围
http://code.jellycan.com/simpleini/
/跨平台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 重新介绍指定的 locale

UTF-8 不支持目标 locale

源文件必须具有 UTF-8 BOM

因此,一个简单的答案是为了这个特定的目的 VC2005+ 损坏,不提供符合符合符合编译路径。 获得行的唯一方法 Unicode 在编译计划是通过 UTF-8 + BOM + wchar, 什么意思是我需要将所有行转换回来 UTF-8 在使用过程中。

没有简单的跨平台转换方法 wchar 在 UTF-8, 例如,尺寸和编码是什么 wchar? 在 Windows, UTF-16. 在其他平台上? 她正在变化。 熟悉
http://icu-project.org/docs/pa ... .html
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/"/;

二哥

赞同来自:

皮椒,

我有完全相同的问题,我刚刚偶然发现了一个不需要将原始行转换为宽字符和返回的解决方案:将源文件保存为 UTF-8

没有

签名,和 VC2008 留下他一个人。 当我意识到重置签名时完美的工作。 总结:

Unicode /UTF-8 没有签名/ - 代码 65001, 不会丢掉警告 c4566 在 VC2008 而不是强迫 VC 使用编码,而代码页 65001 /UTF-8 带签名/ 抛出 c4566 /你怎么找到的/.

我希望帮助您并不为时已晚,但它可以加快您的应用程序 VC2008, 删除你的解决方法。

三叔

赞同来自:

虽然它可能更好地使用宽线,但随后根据需要转换它们 UTF-8. 我认为你最好像你已经提到过的,使用 hex escapes 在行中。 例如,假设 , 你需要什么代码点
\uC911

, 你可以做到。


const char *str = "\xEC\xA4\x91";


我认为它会很好,只是不是很可读,所以如果你这样做,请评论它来解释。

奔跑吧少年

赞同来自:

文件 / 扩展

保存 Options/Encoding: "Unicode /UTF-8 without signature / - Codepage 65001"

三叔

赞同来自:

Visual C++ /2005+/ COMPILER 源文件的标准行为:

CP1252 /例如,西欧代码页/:


"Ä"


C4 00



'Ä'


C4



L"Ä"


00C4 0000



L'Ä'


00C4


UTF-8 没有 BOM:


"Ä"


C3 84 00

/= UTF-8/


'Ä'

→ 警告:多用途常数


"Ω"


E2 84 A6 00

/= UTF-8, 正如预期的那样/


L"A"


00C3 0084 0000

/错误的!/


L'Ä'

→ 警告:多用途常数


L"Ω"


00E2 0084 00A6 0000

/错误的!/

UTF-8 从 BOM:


"Ä"


C4 00

/= CP1252, 不再 UTF-8/,


'Ä'


C4



"Ω"

→ 错误:无法转换为 CP1252!


L"Ä"


00C4 0000

/正确/


L'Ä'


00C4



L"Ω"


2126 0000

/正确/


看,编译器 C 处理文件 UTF-8 没有 BOM 也 CP1252. 因此,编译器无法混合字符串。 UTF-8 和 UTF-16 在编译的输出中! 因此,您必须决定一个源代码文件:

或者

使用 UTF-8 从 BOM 并只生成一行 UTF-16 /即,始终使用前缀
L

/,

或者

UTF-8 没有 BOM 并只生成一行 UTF-8 /即,永远不要使用前缀
L

/.

7位字符 ASCII 没有参与,可以用作前缀
L

, 所以没有它

无论它所如何 EDITOR 可以自动检测文件 UTF-8 没有 BOM 像文件一样 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 包更新 1 并低于修正:

http://support.microsoft.com/kb/980263
....

二哥

赞同来自:

这个怎么样? 您在编码文件中存储字符串 UTF-8, 然后用编码将它们预先用在源文件中 ASCII C++. 您保存编码 UTF-8 在具有十六进制屏蔽的字符串内。 细绳


"中国語 /繁体/"


由B改变。


"\xE4\xB8\xAD\xE5\x9B\xBD\xE8\xAA\x9E /\xE7\xB9\x81\xE4\xBD\x93/"


当然,对于任何人来说,它是不可读的,目标只是为了避免编译器问题。

您可以使用预处理器 C++ 要在转换的头文件中引用行,或转换所有源代码 UTF-8 在 ASCII 在使用此技巧编译之前。

小明明

赞同来自:

从您拥有的任何本机编码的便携式转换 char_traits::widen //.


#include <locale>
#include <string>
#include <vector>

/////////////////////////////////////////////////////////
// NativeToUtf16 - Convert a string from the native
// encoding to Unicode UTF-16
// Parameters:
// sNative /in/: Input String
// Returns: Converted string
/////////////////////////////////////////////////////////
std::wstring NativeToUtf16/const std::string &amp;sNative/
{
std::locale locNative;

// The UTF-16 will never be longer than the input string
std::vector<wchar_t> vUtf16/1+sNative.length///;

// convert
std::use_facet&lt; std::ctype<wchar_t> &gt;/locNative/.widen/
sNative.c_str//,
sNative.c_str//+sNative.length//,
&amp;vUtf16[0]/;

return std::wstring/vUtf16.begin//, vUtf16.end///;
}


从理论上返回路径 UTF-16 到 UTF-8 必须是相同的光,但我发现locali UTF-8 在我的系统中不要正常工作 /VC10 Express 在 Win7/.

所以我写了一个简单的转换器 RFC 3629.


/////////////////////////////////////////////////////////
// Utf16ToUtf8 - Convert a character from UTF-16
// encoding to UTF-8.
// NB: Does not handle Surrogate pairs.
// Does not test for badly formed
// UTF-16
// Parameters:
// chUtf16 /in/: Input char
// Returns: UTF-8 version as a string
/////////////////////////////////////////////////////////
std::string Utf16ToUtf8/wchar_t chUtf16/
{
// From RFC 3629
// 0000 0000-0000 007F 0xxxxxxx
// 0000 0080-0000 07FF 110xxxxx 10xxxxxx
// 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx

// max output length is 3 bytes /plus one for Nul/
unsigned char szUtf8[4] = "";

if /chUtf16 &lt; 0x80/
{
szUtf8[0] = static_cast<unsigned char="">/chUtf16/;
}
else if /chUtf16 &lt; 0x7FF/
{
szUtf8[0] = static_cast<unsigned char="">/0xC0 | //chUtf16&gt;&gt;6/&amp;0x1F//;
szUtf8[1] = static_cast<unsigned char="">/0x80 | /chUtf16&amp;0x3F//;
}
else
{
szUtf8[0] = static_cast<unsigned char="">/0xE0 | //chUtf16&gt;&gt;12/&amp;0xF//;
szUtf8[1] = static_cast<unsigned char="">/0x80 | //chUtf16&gt;&gt;6/&amp;0x3F//;
szUtf8[2] = static_cast<unsigned char="">/0x80 | /chUtf16&amp;0x3F//;
}

return reinterpret_cast<char *="">/szUtf8/;
}


/////////////////////////////////////////////////////////
// Utf16ToUtf8 - Convert a string from UTF-16 encoding
// to UTF-8
// Parameters:
// sNative /in/: Input String
// Returns: Converted string
/////////////////////////////////////////////////////////
std::string Utf16ToUtf8/const std::wstring &amp;sUtf16/
{
std::string sUtf8;
std::wstring::const_iterator itr;

for /itr=sUtf16.begin//; itr!=sUtf16.end//; ++itr/
sUtf8 += Utf16ToUtf8/*itr/;
return sUtf8;
}


我相信它应该在任何平台上工作,但除了我自己的系统外,我无法测试它,所以它可能是错误的。


#include <iostream>
#include <fstream>

int main//
{
const char szTest[] = "Das tausendschöne Jungfräulein,\n"
"Das tausendschöne Herzelein,\n"
"Wollte Gott, wollte Gott,\n"
"ich wär' heute bei ihr!\n";

std::wstring sUtf16 = NativeToUtf16/szTest/;
std::string sUtf8 = Utf16ToUtf8/sUtf16/;

std::ofstream ofs/"test.txt"/;
if /ofs/
ofs &lt;&lt; sUtf8;
return 0;
}


</fstream></iostream></char></unsigned></unsigned></unsigned></unsigned></unsigned></unsigned></wchar_t></wchar_t></vector></string></locale>

君笑尘

赞同来自:

也许尝试进行实验:


#pragma setlocale/".UTF-8"/


或者:


#pragma setlocale/"english_england.UTF-8"/

小姐请别说爱

赞同来自:

我有一个类似的问题。 我的字符串文字 UTF-8 在编译期间被转换为当前的系统代码页面 - 我刚打开了 .obj 文件B. hex-viewer, 他们已经着迷了。 例如,符号

ć

只是一个字节。

对我的解决方案是为了保存 UTF-8 没有 BOM. 这就是我欺骗编译器的方式。 现在他认为它只是一个普通的来源,也没有翻译字符串。 在文件中 .obj

现在有两个字节。

请不要关注一些评论员。 我明白你想要什么 - 我也想要相同的: UTF-8 来源 UTF-8 生成的文件 UTF-8 输入文件, UTF-8 在没有翻译的通信线路上。

也许它会有所帮助......

诸葛浮云

赞同来自:

我知道我为一个派对迟到了,但我想我需要
https://raymai97.github.io/myb ... .html
. 为了 Visual C++ 2005 而以上,如果源文件不包含 BOM /Bayt订购标志/, 和你的系统 locale 不是英文, VC 它将假设您的源文件不在Unicode中。

到您的源文件 UTF-8 你必须正确编制

保存他们 UTF-8 没有

编码 BOM, 和

系统 locale /unicode./ 必须是英语

.

https://i.stack.imgur.com/8W0wd.png

窦买办

赞同来自:

所以,你需要改变一些东西。
现在我有一个解决方案。

首先,您必须在单次契约代码页面下工作 Local, 如 English, 到 cl.exe 没有收到落入混乱的代码。

其次,在UTF8中保存源代码 - 没有编码 BOM, 请注意,没有bom,然后编译
cl.exe, DO 不打电话给任何 C API, 例如, printf wprint, 所有这些员工都不起作用,我不知道为什么:/.... 也许以后我会学习......

然后只是编译并运行,你会看到结果.....
我的电子邮件是loyangan, /Google/ 希望某些人 ......

一个东西 WScript:


#! /usr/bin/env python
# encoding: utf-8
# Yonggang Luo

# the following two variables are used by the target "waf dist"
VERSION='0.0.1'
APPNAME='cc_test'

top = '.'

import waflib.Configure

def options/opt/:
opt.load/'compiler_c'/

def configure/conf/:
conf.load/'compiler_c'/
conf.check_lib_msvc/'gdi32'/
conf.check_libs_msvc/'kernel32 user32'/

def build/bld/:
bld.program/
features = 'c',
source = 'chinese-utf8-no-bom.c',
includes = '. ..',
cflags = ['/wd4819'],
target = 'myprogram',
use = 'KERNEL32 USER32 GDI32'/


执行脚本 run.bat


rd /s /q build
waf configure build --msvc_version "msvc 6.0"
build\myprogram

rd /s /q build
waf configure build --msvc_version "msvc 9.0"
build\myprogram

rd /s /q build
waf configure build --msvc_version "msvc 10.0"
build\myprogram


来源 main.c:


//encoding : utf8 no-bom
#include <stdio.h>
#include <string.h>

#include <windows.h>

char* ConvertFromUtf16ToUtf8/const wchar_t *wstr/
{
int requiredSize = WideCharToMultiByte/CP_UTF8, 0, wstr, -1, 0, 0, 0, 0/;
if/requiredSize &gt; 0/
{
char *buffer = malloc/requiredSize + 1/;
buffer[requiredSize] = 0;
WideCharToMultiByte/CP_UTF8, 0, wstr, -1, buffer, requiredSize, 0, 0/;
return buffer;
}
return NULL;
}

wchar_t* ConvertFromUtf8ToUtf16/const char *cstr/
{
int requiredSize = MultiByteToWideChar/CP_UTF8, 0, cstr, -1, 0, 0/;
if/requiredSize &gt; 0/
{
wchar_t *buffer = malloc/ /requiredSize + 1/ * sizeof/wchar_t/ /;
printf/"converted size is %d 0x%x\n", requiredSize, buffer/;
buffer[requiredSize] = 0;
MultiByteToWideChar/CP_UTF8, 0, cstr, -1, buffer, requiredSize/;
printf/"Finished\n"/;
return buffer;
}
printf/"Convert failed\n"/;
return NULL;
}

void ShowUtf8LiteralString/char const *name, char const *str/
{
int i = 0;
wchar_t *name_w = ConvertFromUtf8ToUtf16/name/;
wchar_t *str_w = ConvertFromUtf8ToUtf16/str/;

printf/"UTF8 sequence\n"/;
for /i = 0; i &lt; strlen/str/; ++i/
{
printf/"x ", /unsigned char/str[i]/;
}

printf/"\nUTF16 sequence\n"/;
for /i = 0; i &lt; wcslen/str_w/; ++i/
{
printf/"x ", str_w[i]/;
}

//Why not using printf or wprintf? Just because they do not working:/
MessageBoxW/NULL, str_w, name_w, MB_OK/;
free/name_w/;
free/str_w/;

}

int main//
{
ShowUtf8LiteralString/"English english_c", "Chinese /Traditional/"/;
ShowUtf8LiteralString/"简体 s_chinese_c", "你好世界"/;
ShowUtf8LiteralString/"繁体 t_chinese_c", "中国語 /繁体/"/;
ShowUtf8LiteralString/"Korea korea_c", "중국어 /번체/"/;
ShowUtf8LiteralString/"What? what_c", "Chinês /Tradicional/"/;
}


</windows.h></string.h></stdio.h>

知食

赞同来自:

我有一个类似的问题,决定是为了保持 UTF8 不使用高级保存参数

窦买办

赞同来自:

UTF-8 源文件

没有 BOM

: 处理为未加工,除非您的系统使用代码页 >1byte/char /例如, Shift JIS/. 您需要将系统代码页更改为任何一个字节,然后您可以在文字中使用Unicode字符并没有问题编译。 /至少我希望/.

从 BOM

: 他们是不是 char 在编译期间,字符串文字将转换为系统代码页。 您可以使用使用的检查当前系统代码 GetACP//. AFAIK, 无法安装系统代码页面 65001 /UTF-8/, 因此,因此,没有办法使用 UTF-8 直接S. BOM.

唯一的便携式和独立编译方法是使用编码 ASCII 和逃生序列,因为没有保证任何编译器将接受编码文件 UTF-8.

帅驴

赞同来自:

汇编字符串的汇编我有一个类似的问题 UTF-8 narrow /char/, 而且我发现我基本需要有喜欢 UTF-8 BOM, 所以我。
#pragma execution_character_set/"utf-8"/

[1], 或者不是偶数 BOM, 没有pragma. [2]. 使用一个没有不同的导致错误的转换。

我详细记录在
https://github.com/jay/compiler_string_test
[1]: Visual Studio 2012 不支持 execution_character_set. Visual Studio 2010 和 2015 它可以很好地工作,并且如您所知,含有补丁 2008 一年它适用。

[2]: 本主题的一些评论指出,既不使用 BOM, Pragma都没有导致使用Multibyte的本地代码页面对开发人员的转换不正确 /例如,日本/.

快网

赞同来自:

我同意神声,令人担忧,等待Westa。 阅读文章。
http://www.joelonsoftware.com/ ... .html

http://www.joelonsoftware.com
...

风见雨下

赞同来自:

阅读文章。 首先,你不想要 UTF-8. UTF-8只是代表角色的方式。 你需要宽符号 /wchar_t/. 你把它们录制为 L"yourtextgoeshere". 这个文字-wchar_t *的类型。 如果你快点,只是看 wprintf.

要回复问题请先登录注册