Windows下的测试以VC2010最为典型,以此为例来讲解。
在编译过程中,处理字符串时会涉及下面两种字符集——
源码字符集(the source character set):源码文件是使用何种编码保存的。
执行字符集(the execution character set):可执行程序内保存的是何种编码。
要想使程序不会乱码,必须满足——
1) 编译器准确识别了源码字符集,从而得到正确的字符串数据。
2) 运行环境的编码与执行字符集相同。运行环境的编码可通过setlocale函数来配置,“setlocale(LC_ALL, "")”表示使用系统默认编码。对于简体中文Windows来说一般是GB2312,如果执行字符集相同,那就能正常显示,否则会乱码。
VC2010是这样处理的——
源码字符集:如果有签名字符,就按它的编码来解析;否则使用本地Locale字符集。
执行字符集:对于char类型,如果有“#pragma execution_character_set”,就按它的编码来存储字符串;否则使用本地Locale字符集。对于wchar_t类型,总是使用UTF-16编码。
当源码使用带签名的UTF-8编码时,VC2010能正确的识别源码字符集是UTF-8。然后因没有“#pragma execution_character_set”,执行字符集是本地Locale字符集——
[VC2010, BOM]
len<1>=5,str=一字A // D2 BB D7 D6 41 ; 因带有BOM,编译器正确的识别了字符串,并将其存储为GB2312字符串。
len<2>=3,str=一字W // 4E00 5B57 0057 ; 因带有BOM,编译器正确的识别了字符串,并将其存储为UTF-16字符串。
当源码使用无签名的UTF-8编码时,VS2010因找不到签名字符,源码字符集被误认为是本地Locale字符集。然后因没有“#pragma execution_character_set”,执行字符集是本地Locale字符集——
[VC2010, noBOM]
len<1>=6,str=一瀛桝 // D2 BB E5 AD 97 41 ; “字A”的UTF-8编码为“E5 AD 97 41”,编译器将它们识别为GB2312编码的“瀛桝”,并将其存储为GB2312字符串。
len<2>=3,str=一瀛梂 // 4E00 701B 6882 ; “字W”的UTF-8编码为“E5 AD 97 57”,编译器将它们识别为GB2312编码的“瀛梂”,并将其存储为UTF-16字符串。
当使用“#pragma execution_character_set("utf-8")”配置了执行字符集为UTF-8后,情况变得更复杂了。我们先看看VC2010能正确识别源码字符集的带签名文件——
[VC2010, BOM, execution_character_set]
len<1>=6,str=一瀛桝 // D2 BB E5 AD 97 41 ; “\u4e00”被识别为“一”,并存储为GB2312编码“D2 BB”。“字A”的UTF-8编码为“E5 AD 97 41”,编译器正确的将其存储为UTF-8编码。但显示时系统默认是 GB2312 编码。
len<2>=3,str=一字W // 4E00 5B57 0057
再看看无签名时的情况。VS2010因找不到签名字符,源码字符集被误认为是本地Locale字符集,即误将UTF-8识别为GB2312。然后根据执行字符集,又转换编码为UTF-8进行存储。最后在运行时因默认编码是GB2312,再次误将UTF-8识别为GB2312——
[VC2010, noBOM, execution_character_set]
len<1>=8,str=一鐎涙 // D2 BB E7 80 9B E6 A1 9D ; “\u4e00”被识别为“一”,并存储为GB2312编码“D2 BB”。“字A”的UTF-8编码为“E5 AD 97 41”,编译器将它们识别为GB2312编码的“瀛桝”,并存储为UTF-8编码的“E7 80 9B E6 A1 9D”。但显示时系统默认是 GB2312 编码。
len<2>=3,str=一瀛梂 // 4E00 701B 6882
从上面这2个例子中,发现VC2010存在一个Bug——“#pragma execution_character_set”对“\u”转义字符无效,“\u”转义字符总是使用本地Locale字符集,而不是执行字符集。
3.2 GCC分析
GCC的源码字符集与执行字符集默认是UTF-8编码,这是因为现在的Linux系统大多使用UTF-8编码。就算调整了Linux系统语言后,只是区域发生了变化,字符编码依然是UTF-8。所以我们的程序在“简体中文”与“英语”下,均能正确的显示中文字符。
MinGW中的GCC也是这样的,源码字符集与执行字符集默认是UTF-8编码。但是简体中文的Windows的默认编码是GB2312,会将printf输出UTF-8字符串误认为是GB2312,造成乱码。
==================================================================================================================================================================
1,源码字符集
2,执行字符集
1,源码字符集:有BOM吗,有则按BOM解释,无则使用本地local字符集(随系统设置而变)
2,执行字符集:使用本地local字符集(随系统设置而变)
1,Unicode规范中有一个BOM的概念。BOM——Byte Order Mark,就是字节序标记。
1,LC_ALL,LANG和LC_*
2,setlocal 是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境。
- 源文件字符集:源文件本身也是文本文件,所以源文件字符集是指源文件保存时采用哪种字符集编码。VC++下源文件默认是gbk编码,如果想要更改,可以通过 文件-高级保存选项 修改某个源文件的编码方式,似乎没有什么选项能够设置创建项目时的源文件编码,需要自己一个一个设。
- 编译器字符集:编译器在读取源代码文件时所使用的内部字符集决定了编译器如何把读入的源代码文件字节流进行转换,转换是指从一种字符集编码的字节经过解码再编码到另一种字符集编码的字节。当然编译器内部采用什么字符集不是我们所关心的,是编译器内部的事情。---javacc????????????????????????????
- 执行字符集:编译器在编译时会将 字符/字符串 常量从上一步编码得到的字节转化为相应的字符集,转化为哪种字符集决定了程序在运行时这些字符串采用了哪种字符集编码,举个例子:
==================================================================================================================================================================================
如何设置语法高亮? SeccureCRT中的终端类型默认是VT100或者Xterm,我们要选择linux。字符集一定要是utf8
============================================================================================================
字符集、codepages、setlocal
2017年09月26日 16:51:18 长大了的暗 阅读数:274
版权声明:醒己、分享、记忆 https://blog.csdn.net/qihangran5467/article/details/78103255
关于字符集
- UTF-8编码文本在VS中乱码解析
- 字符集简介
- Unicode结构
- code pages
- wstring与string相互转换
UTF-8编码文本在VS中乱码解析
windows操作系统中,Unicode字符集用UTF-16实现的,ANSI字符集是根据代码页中设置相关,默认没有用UTF-8,VS读取UTF-8编码的文本文件时,如果遇到中文,不论用string的ANSI解析,还是用wstring的Unicode解析,均会乱码。
字符集简介
一种“字符集”就是字符到内码的映射。目前用得最广泛的就是Unicode,UTF-8是UNICODE的一种实现方式,UNICODE在windows 系统内部用UTF-16实现。用UTF-16,大多数字符能被两个字节代码标识。
编程中发现一些第三方库必须要使用老的字符集。code pages允许应用程序工作在这些老的字符集环境下。老字符集可分为:
1、单字节字符集(SBCS),例如ASCII
2、多字节字符集,特别是双字节字符集(DBCS),例如GBK
注:ASCII、GBK、BIG5等都属于ANSI编码。
Unicode结构
Unicode字符集也被称为Universal Character Set(UCS)。UCS分为UCS-2和UCS-4。UCS-4,4个字节,最高位必为0,UCS-4最高字节7个有效位,128个组合,每个组根据次高字节可分为256个plane。Group 0的Plane 0被称作Basic Multilingual Plane,即BMP。
UTF-16用16位直接表示65536个独立字符,但是BMP不能全部覆盖所有字符。Unicode4.1包括了97000个字符。 Unicode标准建立了16个附加的字符plane,每一个大小都与BMP一样(BMP正是group,plane都为0)。尽管超出BMP的二进制代码没有字符与其一一对应,但是理论上说Unicode可以定义1114112个字符(2¹⁶ * 17),范围为:U+0000到U+10FFFF.
Unicode定义 Supplementary Characters来用UTF-16代表这个大的字符集。关于Supplementary Characters可参考 [ MSDN ]
Code Pages
Code Pages就是unicode与各国文字之间的映射表。前面提到字符集就是字符到内码的映射,Unicode要想转老字符集,就是将按Unicode存放的字符转换到对应老字符集对应的内码,code page就是规定你是按简体中文转,还是按法文转,还是按繁体中文转,但是必须系统支持才能有效。
vs里面通过setlocal指定codepage。值得注意的是,中文windows系统默认的是GBK编码。setlocal操作与下图操作等效。
wstring与string相互转换
///
// wcstombs_s : 此函数转换后最后一个字符始终是null-结束符,
// 因此如果要转换的字符串是“中文”, sizeInByte设置为2,则不能正确转换
// sizeInByte设置为3,可以转换“中”字
// sizeInByte是目标bugggfer的长度!
// 转换终止的3个条件:
// 1 碰到null结束符,也就是说,源字符串转换完毕
// 2 碰到宽字符不能转换的情况
// 3 buffer里面存的字符长度(byte)等于count, 也就是说填满了
//
//wstring to string
string ws2s(wstring& in)
{
// 设置code page
setlocale(LC_ALL, "chs");
// 源字符串以及尺寸
const wchar_t* src = in.c_str();
size_t src_len = in.size();
// 目标字符串以及尺寸
size_t dst_len = 2*src_len + 1; //c风格字符串需要一个结束符
char* dst = new char[dst_len];
memset(dst,0,dst_len);
// 转换
size_t pReturnValue = 0;
errno_t error_info = wcstombs_s(
&pReturnValue, //size_t *pReturnValue,
dst, //char *mbstr,
dst_len, //size_t sizeInBytes,
src, //const wchar_t *wcstr,
_TRUNCATE //size_t count
);
//
string out = dst;
delete[] dst;
setlocale(LC_ALL, "C");
return out;
}
//string to wstring
wstring s2ws(string& in)
{
wstring out;
setlocale(LC_ALL, "chs");
const char* src = in.c_str();
size_t dst_len = in.size() + 1;
wchar_t* dst = new wchar_t[dst_len];
memset(dst,0,dst_len);
size_t return_num;
mbstowcs_s(&return_num, dst, dst_len, src, _TRUNCATE);
out = dst;
setlocale(LC_ALL, "C");
delete[] dst;
return out;
}
目录
用 [TOC]
来生成目录:
===========================================================================================================================================================================================================================================================================
C++中的locale设置
2012年03月14日 17:04:51 koudaidai 阅读数:10481
C/C++程序中,locale将决定程序所使用的当前语言编码、日期格式、数字格式及其它与区域有关的设置,locale设置的正确与否将影响到程序中字符串处理(wchar_t如何输出、strftime()的格式等)。因此,对于每一个程序,都应该慎重处理locale设置。
C locale和C++ locale是独立的。C locale用setlocale(LC_CTYPE, “”)初始化,
C++ locale用std::locale::global(std::locale(“”))初始化。这样就可以根据当前运行环境正确设置locale。
根据环境变量中设置编码信息
使用第二个参数为”"的setlocale()调用会自动根据LC_ALL、LC_CTYPE和LANG环境变量的值设置合适的值。
-
#include <locale.h>
-
#include <locale>
-
using std::locale;
-
int main()
-
{
-
setlocale(LC_CTYPE, "");
-
// 使用当前locale,但numpunct使用缺省的,因此不会在输出数字时加上千位分隔符
-
locale::global(locale("").combine<std::numpunct<char> >(locale::classic()));setlocale()的有效的locale串
setlocale()的有效的locale串
在windows下可以用”.codepage”如”.936″来指定,linux下可以指定得更详细:”zh_CN.GB18030″。
windows下不能直接指定“GB18030”,可能只能用“GBK”。
检测当前的语言环境是否使用了 UTF-8 编码
-
先用setlocale()设置编码,再用nl_langinfo()进行检测
为检测当前语言环境是否使用了 UTF-8 编码。首先必须调用 setlocale(LC_CTYPE, “”) 函数,依据环境变量设置语言环境。nl_langinfo(CODESET) 函数也是由 locale charmap 命令调用,从而查找当前语言环境指定的编码名称。
-
BOOL utf8_mode = FALSE;
-
if(!strcmp(nl_langinfo(CODESET), "UTF-8")
-
utf8_mode = TRUE;•直接查询环境变量
-
这项测试假设 UTF-8 语言环境名称中有值“UTF-8”,但实际情况并不总是如此,所以应该使用 nl_langinfo() 方法。
-
char *s;
-
BOOL utf8_mode = FALSE;
-
if ((s = getenv("LC_ALL")) || (s = getenv("LC_CTYPE")) || (s = getenv ("LANG")))
-
{
-
if (strstr(s, "UTF-8"))
-
utf8_mode = TRUE;
-
}
==================================================================================================================================================================================
QString乱谈(2)
2012年05月07日 03:02:23 dbzhang800 阅读数:24442
- 长期以来,很多人都清楚,一旦C++源码中直接使用了中文,这样的源码想要跨平台(I18N)会非常困难。
随着:
- Windows下:MSVC2010成为主流
- Linux下:GCC升级到4.6
C++中的中文问题 才算有了一个比较优雅的、跨平台的Workaround。
(本文讨论编译器范围:GCC4.6+, MSVC2010sp1+ 。本文属于QString系列,但暂不涉及QString)
C++ 中文问题
要在C++中正确使用中文,必须要了解下面两个概念:
源码字符集(the source character set) | 源码文件是使用何种编码保存的 |
执行字符集(the execution character set) | 可执行程序内保存的是何种编码(程序执行时内存中字符串编码) |
C++98的问题: 既没有规定源码字符集,也没有规定执行字符集
这个... 如何理解?不妨看个例子
例子
这个要求高么?
- 一个简单的C++程序,只是希望它能在简体中文Windows、正体中文Windows、英文版Windows、Linux、MAC OS...下的结果一致。
//main.cpp int main() { char mystr[] = "老老实实的学问,来不得半点马虎"; return sizeof mystr; }
可以试着反问自己两个问题
- 这个源码文件是何种编码保存的?(有确定答案么?)
- mystr中是什么内容?(有确定答案么?)
对C++来说,这两个都不确定。
- 固定平台的话,还能忍忍
- 要跨平台的话,这种东西...
GCC
在GCC下,这两个都可以使用你自己喜好的编码(如果不指定,默认都是UTF8)
-finput-charset=charset -fexec-charset=charset
除了前两个选项外,还有一个:
-fwide-exec-charset=charset
wide? 不妨先猜一下它是干嘛的
MSVC
MSVC没有类似前面的选项。
源码字符集如何解决? | 有BOM么,有则按BOM解释,无则使用本地Locale字符集(随系统设置而变) |
执行字符集如何解决? | 使用本地Locale字符集(随系统设置而变) |
挺霸道哈(当然,源码中可以使用#pragma setlocale("..."),但功能很有限,比如Windows没有utf8的locale,所以...)。
另外,和GCC对应的wide-exec-charset呢?
宽执行字符集如何解决? | 不妨先考虑一下 |
怎么办?
这才两个编译器,看起来就这么复杂了。而C++编译器的数目远大于2.
要想跨平台,必须确保这两个字符集都是“确定”的,而能胜任该任务的字符集,似乎理想的也只能是...
UTF-8方案
-
如果我们将源码保存成utf8,执行字符集也选为utf8,那么天下将太平了。使用非ASCII字符的源码文件也就可以在不同国家的用户间无障碍流通了 ;-).
源码保存成UTF-8没有什么困难,但是,执行字符集需要是UTF-8。没那么简单
对GCC来说,这个问题很简单(默认的编码选项足够了):
- 只要源码文件保存成utf8即可(带或不带BOM均可)
- 早期的gcc不接收带BOM的utf8源码文件,现在,至少在GCC4.6中,这一限制不再存在。
对MSVC来说,这个问题异常复杂:
- 对MSVC2003来说,只要源码保存成不带BOM的utf8即可
- 对MSVC2005、(没在SP1基础上装热补丁的)MSVC2008来说。完全没办法
- 直到MSVC2010sp1,才算提供了一个解决方案。源码保存成带BOM的utf8,utf16,...,然后添加
#pragma execution_character_set("utf-8")
要想跨GCC4.6+和MSVC2010sp1+,我们需要取它们的交集:也就是
- 源码保存成带BOM的utf8
-
为MSVC添加#pragma
//main.cpp #if _MSC_VER >= 1600 #pragma execution_character_set("utf-8") #endif int main() { char mystr[] = "老老实实的学问,来不得半点马虎"; return sizeof mystr; }
C++11
等到MSVC支持C++11的String Literals之时,我们就没必要用那个蹩脚的pragma了,直接
char mystr[] = u8"老老实实的学问,来不得半点马虎";
即可(尽管现在在GCC下没问题,但要跨平台,估计要等到Visual C++ 12了)。
有个问题?
C++98中不是有个wchar_t么,它不是用来表示unicode字符的么?
Unicode 4.0标准的5.2节是如何说的:
The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compilershould not use wchar_t for storing Unicode text. The wchar_t type is intended forstoring compiler-defined wide characters, which may be Unicode characters in some compilers.
在回头看看GCC的选项
-fwide-exec-charset=charset
尽管GCC为其提供的默认编码是UTF16或UTF32(取决于wchar_t的宽度),但该编码是可以随意设置的。
尽管这个东西不保证跨平台,也很不好玩, 但是,由于在windows下面wchar_t用来表示utf16字符,而且直接对应系统API接口,所以在类型char16_t普及之前,还是很重要的。
C++11执行字符集
前面提到的u8就是C++11为“执行字符集”所做的努力之一。
新明确规定了utf8、utf16和utf32这3种执行字符集。
char* | u8"中文" |
char16_t* | u"中文" |
char32_t* | U"中文" |
可是C++11并没有规定源码字符集
const char* mystr=u8"中文";
C++标准对编译器说,我不管这个文件的具体编码是什么,但你必须给我生成对应utf8编码的字节流。
编译器似乎有点傻了吧?不知道源文件的编码,我如何转换
于是:
MSVC说:源码文件必须有BOM,不然我就认为你是本地locale的编码
GCC说:我认为你就是utf8编码,除非通过命令行通知我其他编码
在C++11标准下,对源码编码 简单的处理办法还是,使用带BOM的UTF8保存。
参考
==================================================================================================================================================================
c++程序编码
c++程序中涉及到中文字符的输入输出以及其他操作经常会出现乱码。乱码主要是由于程序的源文件编码、可执行文件编码以及程序运行环境的编码不匹配导致。比如,c++源程序文件编码为GB18030, 在源程序中有一中文窄字符串常量,程序运行时输出该字符串常量,运行环境的系统编码为UTF8时,就会输出乱码。
一、程序相关的编码
1.程序源文件编码
程序源文件编码是指保存程序源文件内容所使用的编码方案,该编码方案可在保存文件的时候自定义。
通常在简体中文windows环境下,各种编辑器(包括visual studio)新建文件缺省编码都是GB18030,所以不特别指定的话,windows环境下的c++源文件的编码通常为GB18030(GB18030兼容GBK);在linux环境下,默认的为UTF-8编码。
2.c++程序内码
源程序编译后,c++中的字符串常量变成一串字节存放在可执行文件中,内码指的是在可执行文件中,字符串以什么编码进行存放。这里的字符串常量指的是窄字符(char)而不是宽字符(wchar_t)。宽字符通常都是以Unicode(VC使用UTF-16BE, gcc使用UTF-32BE)存放。
通常简体中文版的VC使用内码为GB18030,而gcc使用内码缺省为UTF-8,单可以通过-fexec-charset参数进行修改。(可以通过在程序中打印字符串中每个字节的16进制形式来判断程序使用的内码)。
3.运行环境编码
运行环境编码指的是,执行程序时,操作系统或终端所使用的编码。程序中输出的字符最终要转换为运行环境编码才能显示,否则就会出现乱码。
常用的简体中文版的windows环境编码是GB18030,linux下最常用的环境编码是UTF-8。
4.三种编码之间的关系
程序源文件【源文件编码】--->(编译器编译) ---->目标文件【程序内码】----> (运行后输出信息)---->输出【运行环境编码】
编译器需要正确识别源文件的编码,把源文件编译为目标文件,并把源文件中的以源文件编码的字符串转换为以程序内码编制的字符串保存在目标文件中。
如果源程序中的为窄字符串常量,则程序运行时,直接将目标文件中对应的内码字符串输出;若为宽字符串常量,则程序运行时c++标准库需要正确识别终端的运行环境编码,并把程序的输出转换为运行环境所使用的编码,以便正确显示。
二、c++宽窄字符
c++有窄字符char和宽字符wchar_t的区别,分别有一套相应的类和函数(string/cout/strlen和wstring/wcout/wsclen等)。窄字符在不同的编译器下有不同的缺省编码形式(在简体中文VC下是GB18030编码,gcc下是UTF-8编码),宽字符一般都使用unicode编码,在VC下使用UTF-16,gcc下使用UTF-32。
c++在输出窄字符时会按照程序内码原样输出,不会进行编码转换,因此在使用窄字符要求程序内码和运行环境编码一致,才不会出现乱码;
c++在输出宽字符时,会自动转换为运行环境的编码,因此只要正确设置了运行环境编码,同一个程序就可以在不同编码的运行环境下正确显示中文。在程序中设置当前环境的字符编码,通过 locale::global(locale(""))进行设置。
兼容windows和linux的字符显示的做法
对于需要支持多语种的程序,使用窄字符存储字符串常量,源程序中使用ascii字符,对于非ascii字符,如中文等通过gettext等工具放到单独的语言包中。
三、用户输入、输出以及持久化
由于用户输入、输出即从文件、网络等设施读写的数据在程序底层看来都是字节,因此存在输入时如何把字节流解释成有效的信息,在输出时怎么把程序中的信息转换为正确的字节流的问题。
程序不对内容进行处理
如果用户不需要对字节流的内容进行处理,而输入的字符编码和输出的字符编码一致,则程序不需要对数据进行任何的编码转换,只需要把读入的数据原样写到输出即可,数据的字符编码与程序的编码没有关系。
程序需要对内容进行处理
如果程序需要在一定程度上对数据进行处理(如需要判断字符个数、对字符进行比较。在字符串附加或者去掉内容),就要把数据转换为一种明确的字符编码,一般来说是程序内码,再进行处理,在处理后再转换为所需的字符编码进行输出。
1.宽字符程序
如果只需要处理采用当前运行环境字符编码的数据,可以通过ios::imbue(可以指定io流的字符编码),在输入、输出时c++标准库会自动在所指定的字符编码与程序内码之间进行编码转换。如果不使用流的话,也可以通过标准的wcstombs()或者mbstowcs()函数进行当前编码(通过locale::globale()或setlocale()指定)与宽字符之间的转换。
2.窄字符程序
对于窄字符程序,如果数据的字符编码与程序内码一致也不需要进行编码转换,直接处理即可。
四、几个小实验
case 1
在windows简体中文环境下,设置vs2013源文件的编码为utf-8(默认为gb2312,通过“文件”——“高级保存选项”,选择UTF-8),同时设置编译器编译结果的内码为UTF-8(通过在cpp和h文件的头部添加
#pragma once
#pragma execution_character_set("utf-8")
即可),然后使用如下程序:
1 2 3 4 5 6 7 8 9 10 11 |
|
由于简体中文windows的系统环境的编码为GB18030,而源文件被设置成UTF-8编码,同时也指示编译器编译的目标文件的程序内码使用UTF-8编码,那么在输出的时候会将中文输出乱码。
case 2
在windows简体中文环境下,设置vs2013源文件为utf-8编码,而可执行文件的内码保持默认为gb2312:
1 2 3 4 5 6 7 8 9 |
|
编译器会按照utf-8格式解析源文件,并进行编译,编译出可执行程序的内码为gb2312,系统运行环境的编码为GBK,可以正常显示中文。
case 3
(3.0)在windows简体中文环境下,vs2013源文件分别采用gb2312和utf-8编码,可执行程序的内码分别采用gb2312和utf-8编码(四种组合),直接wcout输出宽字符,结果均为空。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
(3.1)在windows简体中文环境下,vs2013源文件分别采用gb2312和utf-8编码,可执行程序的内码分别采用gb2312和utf-8编码(四种组合),imbue设置输出格式为std::locale("chs")或者通过locale::global(locale("")) 设置,然后wcout输出宽字符:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
因为,宽字符在输出时候会自动进行编码格式的转换,对wcout指定了输出流的输出编码,则可以输出正确的结果。
case 4
在windows下使用mysqlconn库连接mysql数据库,由于为了和客户端通信,mysql数据库采用UTF-8编码。在visual studio 2013下程序访问数据库中中文字符的某条属性,在select的时候,需要将中文字符写在源代码中。由于vistual studio默认的源文件编码和可执行程序的内码都是GBK2312,因此在访问mysql数据库的时候中文字符变为乱码从而无法访问。
可以通过将包含中文字符的那个源文件(只需要含中文字符的那个即可,不需要全部)强制编译为UTF-8编码的可执行程序内码,然后访问mysql即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
======================================================================================================================================================================================
GB:国标
unicode:国际化标准组织提出的
UTF-8:utf-8是为了节省unicode的存储资源和传输流量而产生的一种编码方式,其所能表述的字符范围与Unicode是相等的,但是相对于Unicode它更加轻量化
======================================================================================================================================================================================
明文(str)和字节(bytes)数据之间的转换关系就是编码和解码。
从str到bytes叫编码,用encode命令,从bytes到str叫解码,用decode命令
python3中的默认编码就是utf-8
===============================================================
C++
gbk默认编码和IDE的设置及运行环境有关系
- linux关于默认编码的两个环境变量
- 摘要:linux默认编码这里所说的linux默认编码,是指运行时的环境变量。两个重要的环境变量是LC_ALL和LANG,默认编码会影响到javaURLEncode的行为,下面有描述。建议都设置为"zh_CN.UTF-8"。 从harrison2010处抓来。
-
linux默认编码
这里所说的linux默认编码,是指运行时的环境变量。两个重要的环境变量是LC_ALL和LANG,默认编码会影响到java URLEncode的行为,下面有描述。
建议都设置为"zh_CN.UTF-8"。从harrison2010处抓来。
- 以上是linux关于默认编码的两个环境变量的内容,更多 变量 编码 两个 环境 的内容,请您使用右上方搜索功能获取相关信息。
===========================================================================================================================================================================================================================================================================
【转】locale的设定及其LANG、LC_ALL、LANGUAGE环境变量的区别
zz:http://hi.baidu.com/edeed/blog/item/2e99a14440bd8884b2b7dcb1.html
例如zh_CN.GB2312、zh_CN.GB18030或者zh_CN.UTF-8。很多人都不明白这些古里古怪的表达方式。这个外星表达式规定了什么东西呢?这个问题稍后详述,现在只需要知道,这是locale的表达方式就可以了。
locale这个单词中文翻译成地区或者地域,其实这个单词包含的意义要宽泛很多。
Locale是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境。
[oracle@game ~]$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8
[oracle@game ~]$
locale把按照所涉及到的文化传统的各个方面分成12个大类,这12个大类分别是:
1、语言符号及其分类(LC_CTYPE)
2、数字(LC_NUMERIC)
3、比较和排序习惯(LC_COLLATE)
4、时间显示格式(LC_TIME)
5、货币单位(LC_MONETARY)
6、信息主要是提示信息,错误信息,状态信息,标题,标签,按钮和菜单等(LC_MESSAGES)
7、姓名书写方式(LC_NAME)
8、地址书写方式(LC_ADDRESS)
9、电话号码书写方式(LC_TELEPHONE)
10、度量衡表达方式 (LC_MEASUREMENT)
11、默认纸张尺寸大小(LC_PAPER)
12、对locale自身包含信息的概述(LC_IDENTIFICATION)。
所以说,locale就是某一个地域内的人们的语言习惯和文化传统和生活习惯。一个地区的locale就是根据这几大类的习惯定义的,这些locale定 义文件放在/usr/share/i18n/locales目录下面,例如en_US, zh_CN and de_DE@euro都是locale的定义文件,这些文件都是用文本格式书写的,你可以用写字板打开,看看里边的内容,当然出了有限的注释以外,大部分 东西可能你都看不懂,因为是用的Unicode的字符索引方式。
[oracle@game ~]$ cd /usr/share/i18n/locales
[oracle@game locales]$ ls
aa_DJ ar_YE el_GR es_ES fr_CH iso14651_t1 ne_NP so_ET translit_hangul
aa_ER az_AZ el_GR@euro es_ES@euro fr_FR it_CH nl_BE so_KE translit_narrow
aa_ER@saaho be_BY en_AU es_GT fr_FR@euro it_IT nl_BE@euro so_SO translit_neutral
aa_ET bg_BG en_BW es_HN fr_LU it_IT@euro nl_NL sq_AL translit_small
af_ZA bn_BD en_CA es_MX fr_LU@euro iw_IL nl_NL@euro sr_CS translit_wide
am_ET bn_IN en_DK es_NI ga_IE ja_JP nn_NO st_ZA tr_TR
an_ES br_FR en_GB es_PA ga_IE@euro ka_GE no_NO sv_FI tt_RU
ar_AE br_FR@euro en_HK es_PE gd_GB kk_KZ oc_FR sv_FI@euro uk_UA
ar_BH bs_BA en_IE es_PR gez_ER kl_GL om_ET sv_SE ur_PK
ar_DZ byn_ER en_IE@euro es_PY gez_ER@abegede kn_IN om_KE ta_IN uz_UZ
ar_EG ca_ES en_IN es_SV gez_ET ko_KR pa_IN te_IN uz_UZ@cyrillic
ar_IN ca_ES@euro en_NZ es_US gez_ET@abegede kw_GB pl_PL tg_TJ vi_VN
ar_IQ cs_CZ en_PH es_UY gl_ES lg_UG POSIX th_TH wa_BE
ar_JO cy_GB en_SG es_VE gl_ES@euro lo_LA pt_BR ti_ER wa_BE@euro
ar_KW da_DK en_US et_EE gu_IN lt_LT pt_PT ti_ET wal_ET
ar_LB de_AT en_ZA eu_ES gv_GB lv_LV pt_PT@euro tig_ER xh_ZA
ar_LY de_AT@euro en_ZW eu_ES@euro he_IL mi_NZ ro_RO tl_PH yi_US
ar_MA de_BE es_AR fa_IR hi_IN mk_MK ru_RU translit_circle zh_CN
ar_OM de_BE@euro es_BO fi_FI hr_HR ml_IN ru_UA translit_cjk_compat zh_HK
ar_QA de_CH es_CL fi_FI@euro hu_HU mn_MN se_NO translit_cjk_variants zh_SG
ar_SA de_DE es_CO fo_FO hy_AM mr_IN sid_ET translit_combining zh_TW
ar_SD de_DE@euro es_CR fr_BE i18n ms_MY sk_SK translit_compat zu_ZA
ar_SY de_LU es_DO fr_BE@euro id_ID mt_MT sl_SI translit_font
ar_TN de_LU@euro es_EC fr_CA is_IS nb_NO so_DJ translit_fraction
对于de_DE@euro的一点说明,@后边是修正项,也就是说你可以看到两个德国的locale:/usr/share/i18n/locales /de_DE@euro和/usr/share/i18n/locales/de_DE。打开这两个locale定义,你就会知道它们的差别在于 de_DE@euro使用的是欧洲的排序、比较和缩进习惯,而de_DE用的是德国的标准习惯。
上面我们说到了zh_CN.GB18030的前半部分,后半部分是什么呢?大部分Linux用户都知道是系统采用的字符集。
zh_CN.GB2312到底是在说什么? Locale是软件在运行时的语言环境, 它包括语言(Language), 地域 (Territory) 和字符集(Codeset)。一个locale的书写格式为: 语言[_地域[.字符集]]。所以说呢,locale总是和一定的字符集相联系的。下面举几个例子:
1、我说中文,身处中华人民共和国,使用国标2312字符集来表达字符。zh_CN.GB2312=中文_中华人民共和国+国标2312字符集。
2、我说中文,身处中华人民共和国,使用国标18030字符集来表达字符。zh_CN.GB18030=中文_中华人民共和国+国标18030字符集。
3、我说中文,身处中华人民共和国台湾省,使用国标Big5字符集来表达字符。zh_TW.BIG5=中文_台湾.大五码字符集
4、我说英文,身处大不列颠,使用ISO-8859-1字符集来表达字符。 en_GB.ISO-8859-1=英文_大不列颠.ISO-8859-1字符集
5、我说德语,身处德国,使用UTF-8字符集,习惯了欧洲风格。de_DE.UTF-8@euro=德语_德国.UTF-8字符集@按照欧洲习惯加以修正,注意不是de_DE@euro.UTF-8,所以完全的locale表达方式是 [语言[_地域][.字符集] [@修正值]。
其中,与中文输入关系最密切的就是LC_CTYPE,LC_CTYPE规定了系统内有效的字符以及这些字符的分类, 诸如什么是大写字母,小写字母,大小写转换,标点符号、可打印字符和其他的字符属性等方面。而locale定 义zh_CN中最最重要的一项就是定义了汉字(Class“hanzi”)这一个大类,当然也是用Unicode描述的,这就让中文字符在Linux系统 中成为合法的有效字符,而且不论它们是用什么字符集编码的。
怎样设定locale呢?
设定locale就是设定12大类的locale分类属性,即12个LC_*。除了这12个变量可以设定以外,为了简便起见,还有两个变量:LC_ALL和LANG。
它们之间有一个优先级的关系:LC_ALL > LC_* >LANG。
可以这么说,LC_ALL是最上级设定或者强制设定,而LANG是默认设定值。
1、如果你设定了LC_ALL=zh_CN.UTF-8,那么不管LC_*和LANG设定成什么值,它们都会被强制服从LC_ALL的设定,成为 zh_CN.UTF-8。
2、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_*=en_US.UTF-8,并且没有设定LC_ALL的话,那么系统的locale设定以LC_*=en_US.UTF-8。
3、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_*,和LC_ALL均未设定的话,系统会将LC_*设定成默认值,也就是LANG的值zh_CN.UTF-8。
4、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_CTYPE=en_US.UTF-8,其他的LC_*,和LC_ALL均未设定的话, 那么系统的locale设定将是:LC_CTYPE=en_US.UTF-8,其余的 LC_COLLATE,LC_MESSAGES等等均会采用默认值,也就是 LANG的值,也就是LC_COLLATE=LC_MESSAGES=……= LC_PAPER=LANG=zh_CN.UTF-8。
所以,locale是这样设定的:
1、如果你需要一个纯中文的系统的话,设定LC_ALL= zh_CN.XXXX,或者LANG=zh_CN.XXXX都可以,当然你可以两个都设定,但正如上面所讲,LC_ALL的值将覆盖所有其他的locale设定,不要作无用功。
2、如果你只想要一个可以输入中文的环境,而保持菜单、标题,系统信息等等为英文界面,那么只需要设定 LC_CTYPE=zh_CN.XXXX,LANG=en_US.XXXX就可以了。这样LC_CTYPE=zh_CN.XXXX,而LC_COLLATE=LC_MESSAGES=……= LC_PAPER=LANG=en_US.XXXX。
3、假如你高兴的话,可以把12个LC_*一一设定成你需要的值,打造一个古灵精怪的系统: LC_CTYPE=zh_CN.GBK/GBK(使用中文编码内码GBK字符集); LC_NUMERIC=en_GB.ISO-8859-1(使用大不列颠的数字系统) LC_MEASUREMEN=de_DE@euro.ISO-8859-15(德国的度量衡使用ISO-8859-15字符集) 罗马的地址书写方式,美国的纸张设定……。估计没人这么干吧。
4、假如你什么也不做的话,也就是LC_ALL,LANG和LC_*均不指定特定值的话,系统将采用POSIX作为lcoale,也就是C locale。
另外LANG和LANGUAGE有什么区别呢?
LANG - Specifies the default locale for all unset locale variables
LANGUAGE - Most programs use this for the language of its interface
LANGUAGE是设置应用程序的界面语言。而LANG是优先级很低的一个变量,它指定所有与locale有关的变量的默认值,
===========================================================================================================================================================================================================================================================================
LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME
定义于头文件 | ||
#define LC_ALL /*implementation defined*/ | ||
#define LC_COLLATE /*implementation defined*/ | ||
#define LC_CTYPE /*implementation defined*/ | ||
#define LC_MONETARY /*implementation defined*/ | ||
#define LC_NUMERIC /*implementation defined*/ | ||
#define LC_TIME /*implementation defined*/ | ||
上面每个宏常量都展开成拥有相异值的整数常量表达式,适合用作 setlocale 的首个参数。
常量 | 解释 |
LC_ALL | 选择整个 C 本地环境 |
LC_COLLATE | 选择 C 本地环境中的对照类别 |
LC_CTYPE | 选择 C 本地环境中的字符分类类别 |
LC_MONETARY | 选择 C 本地环境中的货币格式化类别 |
LC_NUMERIC | 选择 C 本地环境中的数值格式化类别 |
LC_TIME | 选择 C 本地环境中的时间格式化类别 |
<locale.h>
中可以定义附加宏常量,名称以 LC_
后随至少一个大写字母开始。例如, POSIX 规范要求 LC_MESSAGES (此外还控制 perror 和 strerror ), ISO/IEC 30112:2014 ( 2014 方案)额外定义 LC_IDENTIFICATION 、 LC_XLITERATE 、 LC_NAME 、 LC_ADDRESS 、 LC_TELEPHONE 、 LC_PAPER 、 LC_MEASUREMENT 和 LC_KEYBOARD ,它们均为 GNU C 库所支持(除了 LC_XLITERATE )。
注意
glibc 中的本地环境类别
glibc 除了 C 标准要求的 5 个类别外,还额外支持 7 个类别,以及一个默认项:
glibc 本地环境类别常量 | 解释 |
LC_ADDRESS | 选择 C 本地环境中的邮政地址格式类别 |
LC_IDENTIFICATION | 选择 C 本地环境中的类别版本与状态 |
LC_KEYBOARD | 选择 C 本地环境中的键盘鉴别类别 |
LC_MEASUREMENT | 选择 C 本地环境中的度量系统信息类别 |
LC_NAME | 选择 C 本地环境中的人名书写格式类别 |
LC_PAPER | 选择 C 本地环境中的纸张格式类别 |
LC_TELEPHONE | 选择 C 本地环境中的电话号码格式(和其他电话信息)类别 |
LANG | 选择尚未指定的类别 |
其中 LC_ALL
的优先级高于所有特定类别,而每个特定类别都优先于 LANG
。具体而言:
- 若设置
LC_ALL
为 "zh_CN.UTF-8" ,则不论LC_*
和LANG
原为何值,每个分类都会被设为 "zh_CN.UTF-8" 。 - 若未设置
LC_ALL
,而专门设置LANG
为 "zh_CN.UTF-8" ,并设置某LC_*
为"en_US.UTF-8" ,则其所对应的本地环境类别被设为 "en_US.UTF-8" 。 - 若未设置
LC_ALL
和某些类别的LC_*
,并设置LANG
为 "zh_CN.UTF-8" ,则这些LC_*
所对应的本地环境被设为 "zh_CN.UTF-8" 。
所以,对于不同的目的,应该用不同方式设置本地环境:
- 例如,若需要纯中文的系统,则可调用 setlocale(LC_ALL, "zh_CN.UTF-8") 或 setlocale(LANG, "zh_CN.UTF-8") 。可以但没必要设置二次。
- 若只需要输入中文的环境,而其他界面信息和格式为英文,则可使用
setlocale(LC_CTYPE, "zh_CN.UTF-8"); setlocale(LANG, "en_US.UTF-8");
- 若有特殊的本地环境定制需求,例如使用中文 GBK 字符集、用 ISO-8859-1 字符集的大英数字系统、用 ISO-8859-15 字符集的德国度量系统……,则应逐一设置
LC_*
:
setlocale(LC_TYPE, "zh_CN.GBK/GBK"); setlocale(LC_NUMERIC, "en_GB.ISO-8859-1"); setlocale(LC_MESUREMENT, "de_DE.ISO-8859-15@euro"); // 以及其他类别
- 若只需要应用默认 "C" ( "POSIX" 为其别名)本地环境,则无需任何设置代码。
示例
运行此代码
#include <stdio.h> #include <locale.h> #include <time.h> #include <wchar.h> int main(void) { setlocale(LC_ALL, "en_US.UTF-8"); // C 本地环境将为启用 UTF-8 的英文 setlocale(LC_NUMERIC, "de_DE"); // 小数点将为德文 setlocale(LC_TIME, "ja_JP"); // 日期/时间格式将为日文 wchar_t str[100]; time_t t = time(NULL); wcsftime(str, 100, L"%A %c", localtime(&t)); wprintf(L"Number: %.2f\nDate: %Ls\n", 3.14, str); }
输出:
Number: 3,14 Date: 月曜日 2011年12月19日 18時04分40秒
引用
- C11 standard (ISO/IEC 9899:2011):
- 7.11/3 Localization <locale.h> (p: 224)
- C99 standard (ISO/IEC 9899:1999):
- 7.11/3 Localization <locale.h> (p: 205)
- C89/C90 standard (ISO/IEC 9899:1990):
- 4.4 LOCALIZATION <locale.h>
参阅
获取和设置当前 C 本地环境 (函数) |