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表上的插入操作周围抛出的异常。例外告诉我他们遇到不正确的字符串值。我想它是由错误的编码造成的吗?顺便说一句,有没有其他方法来处理这个问题?
AFAIK,VC ++没有命令行标志,可以指定UTF-8执行字符集。然而,它(偶尔)支持无证件
#pragma execution_character_set("utf-8")
提到here。
要使用此pragma获取命令行标志的效果,您可以在头文件中编写pragma,例如preinclude.h
,并通过传递标志/FI preinclude.h
在每个编译中预先包含此标头。有关如何从IDE设置此标志,请参阅this documentation。
该编译指示在VC ++ 2010中得到支持,然后在VC ++ 2012中被遗忘,并在VC ++ 2013中再次得到支持
应该注意的是,pragma execution_character_set
似乎只适用于字符串文字("Hello World"
)而不适用于宽字符串文字(L"Hello World"
)。
我做了一些实验来了解如何在MSVC中实现源和执行字符集。我在Windows系统上使用Visual Studio 2015进行了实验,其中CP_ACP
是1252,并总结如下结果:
字符文字
CP_ACP
。如果Unicode字符不在CP_ACP
的范围内,则MSVC发出C4566警告(“由通用字符名''U0001D575表示的字符'无法在当前代码页(1252)中表示”)。 MSVC假定编译软件的执行字符集是编译器的CP_ACP
。这意味着你应该在目标环境的CP_ACP
下编译软件,即如果你想在代码页为1252的Windows系统上执行软件,你应该在代码页1252下编译它而不是在任何其他系统上执行它。代码页。实际上,如果您的文字是ASCII编码(C0控制和基本拉丁语Unicode块),它可能会起作用,因为大多数常见的SBCS代码页扩展了这种编码。但是,有一些没有,特别是DBCS代码页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
字符0xFF
是否是Unicode字符U+00FF
。我没有机会在DBCS Windows系统上重复我的实验,因为我不会说通常使用这些代码页的语言。也许有些人可以在这样的系统上重复实验。
对我来说,实验的结论是你应该避免使用字符文字,即使你使用execution_character_set
编译指示。
该pragma只是更改了二进制文件中字符串文字的编码方式,但不会更改您使用的库或内核的执行字符集。如果你想使用execution_character_set
编译指示,你必须使用pragma重新编译Windows和你完全使用的所有其他库,这当然是不可能的。所以我建议不要使用它。它可能适用于某些系统,因为UTF-8适用于CRT中的大多数字符串函数,而CP_ACP
通常包含ASCII,但您应该检查这些假设是否真的存在于您的目标环境中,以及这种误用所需的努力是否真的值得。此外,该pragma似乎没有文档,我可能不会在将来的版本中工作。
否则,您必须为目标系统中使用的所有代码页编译单独的二进制文件。避免多个二进制文件的唯一方法是将所有字符串外部化为UTF-16LE编码的资源,并在需要时将字符串转换为CP_ACP
。在这种情况下,您必须将资源脚本(.rc
文件)保存为UTF-8,使用rc
调用/c65001
(UTF-16LE不起作用)并包含目标系统中正在使用的所有代码页的字符串。
我建议使用Unicode编码(例如UTF-8或UTF-16LE)对文件进行编码,如果不能将字符串外部化为资源并使用UNICODE
和_UNICODE
定义编译,则使用宽字符文字。不管怎么说,不建议使用字符串和字符文字,而不喜欢资源。使用WideCharacterToMultiByte
和MultiByteToWideChar
作为期望根据CP_ACP
或其他代码页编码的字符串的函数。
MSVC的源编码检测启发式最适合启用BOM(即使在UTF-8中)。
我不是亚洲语言的专家,但我读到汉语中的统一是有争议的。因此,使用Unicode可能不是所有问题的解决方案,并且可能存在不符合要求的情况,但我会说,对于大多数语言,Unicode在Windows下最有效。
微软没有明确这一点并记录其编译器和操作系统的行为是错误的。
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,但不设置源字符集或执行字符集。
感谢@ user3998276的回答和伟大的实验。
结论告诉了我很多
至于你的问题,我认为'对db表的插入操作'只是对db插入API的调用。因此,您需要做的就是在UTF8中组织命令,如SQL。一旦API可以理解您的命令,它就可以为您编写正确的值(想象二进制蒸汽)。
尝试:
u8"INSERT INTO table_name (col1, col2,...) VALUES (v1, v2,....)"
http://en.cppreference.com/w/cpp/language/string_literal
QByteArray x = mySql.toUtf8()
。 QByteArray只是'byte of array',因此您可以将static_cast转换为插入API所需的类型。再次仔细阅读@ user3998276的答案,如果有一些字符无法在您的ANSI代码页中表示,则可能需要将cpp文件的编码更改为Unicode。