对处理字符串存储(如果它关心)和打印时系统正在使用的编码感到好奇。
问题1:如果我在std :: string中存储一个字节的字符串或在std :: wstring中存储两个字节的字符串,那么基础整数值会根据当前使用的编码而有所不同吗? (我记得Bjarne说编码是char和整数之间的映射,所以char应该作为整数存储在内存中,不同的编码不一定有相同的映射)
问题2:如果是正面的,std :: string和std :: wstring必须具备编码本身的知识(虽然另一个人告诉我这不是真的)?否则,如何将char转换为正确的整数并存储它们?系统如何知道编码?
问题3:一个特定系统中的默认编码是什么,以及如何更改它(它是所谓的“语言环境”)?我想同样的机制很重要吗?
问题4:如果我用std :: cout在屏幕上打印一个字符串,它的编码是相同的吗?
答案 0 :(得分:4)
(我记得Bjarne说过 encoding是char之间的映射 和整数(s)所以char应该是 作为整数存储在内存中)
不完全。确保你理解一个重要的区别。
编码正在将字符序列转换为字节序列。 解码正在将字节序列转换为字符序列。
对于C和C ++程序员来说,令人困惑的是 char
表示字节,而不是字符!字节类型的名称char
是来自Unicode之前的遗留物每个人(东亚人除外)使用单字节编码的日子。但是现在,我们有Unicode,其编码方案每个字符最多4个字节。
问题1:如果我存储一个字节的字符串 在std :: string或两个字节的字符串中 std :: wstring,将底层 整数值取决于编码 目前正在使用?
是的,它会的。假设你有std::string euro = "€";
那么:
问题3:什么是默认值 在一个特定的系统中编码,和 如何改变它(它是所谓的 “区域设置”)?
取决于平台。在Unix上,可以将编码指定为LANG
环境变量的一部分。
~$ echo $LANG
en_US.utf8
Windows有一个GetACP
函数来获取“ANSI”代码页码。
问题4:如果我打印一个字符串怎么办? 用std :: cout到屏幕,是吗 相同的编码?
不一定。在Windows上,命令行使用“OEM”代码页,这通常与其他地方使用的“ANSI”代码页不同。
答案 1 :(得分:1)
编码和解码本质上是相同的过程,即它们都将一个整数序列变换为另一个整数序列。
编码和解码之间的区别在于概念层面。当您“解码”某个字符时,您将以已知编码(“字符串”)编码的整数序列转换为系统特定的整数序列(“text”)。当你“编码”时,你正在将系统特定的整数序列(“text”)转换为以特定编码编码的整数序列(“string”)
这种差异是概念性的,而不是物理的,记忆仍然将解码的“文本”保存为“字符串”;然而,由于特定系统始终以特定编码表示“文本”,因此文本转换不需要处理实际系统编码的特定性,并且可以安全地假设能够处理一系列概念性“字符”而不是“字节”。
然而,通常,用于“文本”的编码使用具有易于使用的属性的编码(例如,固定长度字符,字符和字节序列之间的简单一对一映射等);而编码的“字符串”使用有效的编码进行编码(例如,可变长度字符,依赖于上下文的编码等)
Joel On Software对此进行了撰写:http://www.joelonsoftware.com/articles/Unicode.html
答案 2 :(得分:0)
问题1:如果我存储一个字节的字符串 在std :: string或两个字节的字符串中 std :: wstring,将底层 整数值因不同而异 目前正在使用的编码? (我记得 Bjarne说编码是 char和整数之间的映射 char应存储为整数 记忆,不同的编码不 必须有相同的映射)
你有点想着这个倒退。不同的编码将基础整数解释为不同的字符(或者字符的一部分,如果我们讨论的是多字节字符集),具体取决于编码。
问题2:如果是肯定的,std :: string和std :: wstring必须有 编码的知识 他们自己(虽然另一个人说 我这不是真的)?否则怎么样 是否能够将char转换为 正确的整数并存储它们?怎么样 系统知道编码吗?
std::string
和std::wstring
都是完全编码不可知的。就C ++而言,它们只是分别存储char
个对象和wchar_t
个对象的数组。唯一的要求是char
是一个字节,wchar_t
是一些实现定义的宽度。 (通常在Windows上为2个字节,在Linux / UNIX上为4个字节)
问题3:什么是默认值 在一个特定的系统中编码,和 如何改变它(它是所谓的 “区域设置”)?
这取决于平台。 ISO C ++仅讨论全局语言环境对象std::locale()
,它通常是指您当前系统特定的设置。
问题4:如果我打印一个字符串怎么办? 用std :: cout到屏幕,是吗 相同的编码?
通常,如果通过stdout输出到屏幕,则会根据系统当前的区域设置来解释和呈现您显示的字符。
答案 3 :(得分:0)
任何使用编码的人都应该阅读这篇Joel on Software文章:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)。当我开始使用编码时,我发现它很有用。
C / C ++程序员习惯将字符视为字节,因为几乎每个人都开始使用ascii character set,将整数0-255映射到符号,如字母和阿拉伯数字。事实上,C问题1:如果我在std :: string中存储一个字节的字符串或在std :: wstring中存储两个字节的字符串,那么基础整数值会根据当前使用的编码而有所不同吗?
char
数据类型实际上是一个字节,这无关紧要。
std::string
类将数据存储为8位整数,std::wstring
将数据存储为16位整数。这两个类都不包含任何编码概念。您可以使用任何8位编码,例如ASCII,UTF-8,Latin-1,Windows-1252和std::string
,以及任何8位或16位编码,例如UTF-16,std::wstring
。
std::string
和std::wstring
中存储的数据必须始终由某些编码解释。当您与操作系统交互时,这通常会发挥作用:从文件,流中读取或写入数据,或者进行与字符串交互的OS API调用。
所以要回答你的问题,如果你在std::string
和std::wstring
中存储相同的字节,内存将包含相同的值({{1除外)将包含一个空字节),但该字节的解释将取决于使用的编码。
如果在每个字符串中存储相同的字符,则字节可能会有所不同,这取决于编码。例如,Euro symbol(€)可能使用UTF-8编码存储在wstring
中,该编码对应于字节0xE2 0x82 0xAC。在std::string
中,它可能使用UTF-16编码存储,即0x20AC字节。
问题3:一个特定系统中的默认编码是什么,以及如何更改它(它是所谓的“语言环境”)?我想同样的机制很重要吗?
是的,语言环境决定了OS如何解释其API边界的字符串。 Locale定义的不仅仅是编码。它们还包括有关如何格式化金钱,日期,时间和其他内容的信息。在Linux或OS X上,您可以使用终端中的std::wstring
命令查看当前的语言环境:
locale
所以在这种情况下,我的语言环境是加拿大英语。每个语言环境都定义了用于解释字符串的编码。在这种情况下,语言环境名称清楚地表明它使用的是UTF-8编码,但您可以运行mch@bohr:/$ locale
LANG=en_CA.UTF-8
LC_CTYPE="en_CA.UTF-8"
LC_NUMERIC="en_CA.UTF-8"
LC_TIME="en_CA.UTF-8"
LC_COLLATE="en_CA.UTF-8"
LC_MONETARY="en_CA.UTF-8"
LC_MESSAGES="en_CA.UTF-8"
LC_PAPER="en_CA.UTF-8"
LC_NAME="en_CA.UTF-8"
LC_ADDRESS="en_CA.UTF-8"
LC_TELEPHONE="en_CA.UTF-8"
LC_MEASUREMENT="en_CA.UTF-8"
LC_IDENTIFICATION="en_CA.UTF-8"
LC_ALL=
以查看有关当前编码的更多信息:
locale -ck LC_CTYPE
如果要使用编码测试程序,可以将LC_ALL环境变量设置为要使用的语言环境。您还可以使用mch@bohr:/$ locale -ck LC_CTYPE
LC_CTYPE
ctype-class-names="upper";"lower";"alpha";"digit";"xdigit";"space";"print";"graph";"blank";"cntrl";"punct";"alnum";"combining";"combining_level3"
ctype-map-names="toupper";"tolower";"totitle"
ctype-width=16
ctype-mb-cur-max=6
charmap="UTF-8"
... output snipped ...
更改区域设置。永久更改区域设置取决于您的分发。
在Windows上,大多数API函数都采用窄格式和宽格式。例如,setlocale
包含GetCurrentDirectoryW(Unicode)和GetCurrentDirectoryA(ANSI)变体。在此上下文中,Unicode表示UTF-16。
我不太了解Windows如何设置语言环境,除了尝试语言控制面板。
问题4:如果我用std :: cout在屏幕上打印一个字符串,它的编码是相同的吗?
当您将字符串打印到[GetCurrentDirectory][9]
时,操作系统将在语言环境的编码集中解释该字符串。如果您的字符串是UTF-8编码且操作系统使用Windows-1252,则需要将其转换为该编码。一种方法是使用iconv库。