GCC有-finput-charset
,-fexec-charset
和-fwide-exec-charset
三个编译选项来指定“编译链”中涉及的特定编码。如下所示:
+--------+ -finput-charset +----------+ -fexec-charset (or) +-----+
| source | -------------------> | compiler | -----------------------> | exe |
+--------+ +----------+ -fwide-exec-charset +-----+
我在这里找到了关于-finput-charset
的问题:Specification of source charset encoding in MSVC++, like gcc “-finput-charset=CharSet”。但我想知道VC
是否在GCC中有一个编译器选项,如-fexec-charset
,指定执行字符集。
我在Visual Studio中找到了一个相似的选项:Project Properties/Configuration Properties/General/Character Set
。值为Use Unicode Character Set
。它与GCC中的-fexec-charset
做的相同吗?这样我想将执行字符集设置为 UTF-8 。怎么样?
我正在用C ++编写一个需要与db服务器通信的应用程序。桌子的字符集是utf8。在构建一些测试之后,测试将捕获在db表上的插入操作周围抛出的异常。例外告诉我他们遇到不正确的字符串值。我想它是由错误的编码造成的吗?顺便说一句,有没有其他方法来处理这个问题?
答案 0 :(得分:7)
AFAIK,VC ++没有命令行标志,可以指定UTF-8执行字符集。 然而,它(偶尔)支持未记录的
#pragma execution_character_set("utf-8")
提到here。
要使用此pragma获取命令行标志的效果,可以在标头中编写pragma
文件,比方说,preinclude.h
并通过传递在每个编译中预先包含此标题
国旗/FI preinclude.h
。见this documentation
有关如何从IDE设置此标志。
VC ++ 2010支持该编译指示,然后在VC ++ 2012中被遗忘,并再次受到支持 在VC ++ 2013中
答案 1 :(得分:2)
应该注意的是,pragma execution_character_set
似乎只适用于字符串文字("Hello World"
)而不是宽字符串文字(L"Hello World"
)。
我做了一些实验来了解如何在MSVC中实现源和执行字符集。我在Windows系统上使用Visual Studio 2015进行了实验,其中CP_ACP
为1252,并按如下方式汇总结果:
字符文字
如果MSVC将源文件确定为Unicode文件,即它以UTF-8或UTF-16编码,则会将字符转换为CP_ACP
。如果Unicode字符不在CP_ACP
范围内,则MSVC会发出C4566警告("由通用字符名称表示的字符' \ U0001D575'无法在当前代码中表示第(1252)页")。 MSVC假定编译软件的执行字符集是编译器的CP_ACP
。这意味着你应该在目标环境的CP_ACP
下编译软件,即如果你想在带有代码页1252的Windows系统上执行软件,你应该在代码页1252下编译它而不是在系统与任何其他代码页。实际上,如果您的文字是ASCII编码(C0控制和基本拉丁语Unicode块),它可能会起作用,因为大多数常见的SBCS代码页扩展了这种编码。但是,有一些没有,特别是DBCS代码页
如果MSVC确定源文件不是Unicode文件,它会根据CP_ACP
解释源文件,并假定执行字符集为CP_ACP
。与Unicode文件一样,您应该在目标环境的CP_ACP
下编译软件并遇到同样的问题。
所有" ANSI" Windows API函数(例如CreateFileA
)根据LPSTR
或CP_ACP
(默认为CP_THREAD_ACP
)解释CP_ACP
类型的字符串。要找出哪些函数使用CP_ACP
或CP_THREAD_ACP
并不容易,因此最好永远不要更改CP_THREAD_ACP
。
宽字符文字
宽字符文字的执行字符集始终为Unicode,编码为UTF-16LE。所有宽字符Windows API函数(例如CreateFile
)都将类型LPWSTR
的字符串解释为UTF-16LE字符串。这也意味着wcslen
不返回Unicode字符的数量,而是返回宽字符串的wchar_t
个字符。在某些情况下,UTF-16也与UCS-2不同。
CP_ACP
读取文件并将字符扩展为两个字节而不解释它们。也就是说,如果某个字符在0xFF
中编码为CP_ACP
,则无论0x00 0xFF
字符CP_ACP
是否为Unicode字符,它都将被写为0xFF
{ {1}}。我还没有机会在DBCS Windows系统上重复我的实验,因为我不会说通常使用这些代码页的语言。也许有些人可以在这样的系统上重复实验。
对我来说,实验的结论是你应该避免性格
文字,即使您使用U+00FF
编译指示。
pragma只是更改二进制文件中字符串文字的编码方式,但不会更改您使用的库或内核的执行字符集。如果您想使用execution_character_set
编译指示,则必须使用编译指示重新编译Windows和您完全使用的所有其他库,这当然是不可能的。所以我建议不要使用它。它可能适用于某些系统,因为UTF-8适用于CRT中的大多数字符串函数,而execution_character_set
通常包含ASCII,但是您应该检查这些假设是否真的存在于您的目标环境中以及这种误用所需的努力是否是真的很值得。此外,该pragma似乎没有文档,我可能不会在将来的版本中工作。
否则,您必须为目标系统中使用的所有代码页编译单独的二进制文件。避免多个二进制文件的唯一方法是将所有字符串外部化为UTF-16LE编码的资源,并在需要时将字符串转换为CP_ACP
。在这种情况下,您必须将资源脚本(CP_ACP
文件)保存为UTF-8,使用.rc
调用rc
(UTF-16LE不起作用)并包含所有代码的字符串目标系统中使用的页面。
我建议使用Unicode编码对文件进行编码,例如UTF-8或UTF-16LE,如果不能将字符串外部化为资源并使用/c65001
进行编译,请使用宽字符文字。和UNICODE
已定义。不管怎样,不建议使用字符串和字符文字,更喜欢资源。对于期望根据_UNICODE
或其他代码页编码的字符串的函数,请使用WideCharacterToMultiByte
和MultiByteToWideChar
。
MSVC的源编码检测启发式最适合启用BOM(即使在UTF-8中)。
我不是亚洲语言专家,但我读到有关Unicode的统一是有争议的。因此,使用Unicode可能不是所有问题的解决方案,并且可能存在不满足要求的情况,但我认为对于大多数语言而言,Unicode在Windows下最有效。
微软不明白这一点,并记录其编译器和操作系统的行为。
答案 2 :(得分:1)
Visual Studio 2015 Update 2及更高版本supports setting the execution character set:
您可以使用结合/utf-8
和/source-charset:utf-8
选项的/execution-charset:utf-8
选项。从上面的链接:
在已经存在无BOM的UTF-8文件或更改为BOM的问题的情况下,使用/ source-charset:utf-8选项正确读取这些文件。
在Linux和Windows之间使用/ execution-charset或/ utf-8可以提供帮助,因为Linux通常使用无BOM的UTF-8文件和UTF-8执行字符集。
Project Properties/Configuration Properties/General/Character Set
仅设置宏Unicode / MBCS,但不设置源字符集或执行字符集。