C++中的字符串字面量在内存中是如何存储的?

3

我有一个关于C++中字符串字面值在内存中如何存储的问题。我知道char按照它们的ASCII码存储,但我更关心Unicode字符集。原因是我试图处理一些本地化问题。假设我想要将小写字符转换为大写字符。这在Xcode终端中可以实现。

#include <iostream>
#include <string>
#include <cctype>
#include <clocale>

using namespace std;

int main()
{
wcout.imbue(std::locale("sv_SE.Utf-8"));
const std::ctype<wchar_t>& f = std::use_facet< std::ctype<wchar_t> >(std::locale("sv_SE.Utf-8"));

wstring str {L"åäö"}; // Swedish letters

f.toupper(&str[0], &str[0] + str.size());

std::wcout << str.length() << std::endl;
std::wcout << str << std::endl;
}

Output:
3
ÅÄÖ

然而,当我试图在OS X终端中运行它时,我得到的是一堆垃圾。

Output:
3
ÅÄÖ

当我向用户提示输入时,

#include <iostream>
#include <string>
#include <cctype>
#include <clocale>

using namespace std;

int main()
{
wcin.imbue(std::locale(""));
wcout.imbue(std::locale("sv_SE.Utf-8"));
const std::ctype<wchar_t>& f = std::use_facet< std::ctype<wchar_t> >(std::locale("sv_SE.Utf-8"));

//wstring str {L"åäö"};
wcout << "Write something>> ";
wstring str;
getline(wcin, str);

f.toupper(&str[0], &str[0] + str.size());

std::wcout << str.length() << std::endl;
std::wcout << str << std::endl;
}

我从Xcode终端获得垃圾信息,

Output:
Write something>> åäö
6
åäö

当我使用这些字母时,OS X终端实际上会挂起。可以修改wcin流来假设C编码wcin.imbue(std::locale());,在Xcode中仍然给出相同的输出,但在OS X终端中则会得到以下结果:

Output:
Write something>> åäö
3
ŒŠš

因此,问题显然与编码有关。我想知道在C++中字符串文字实际上是如何存储在内存中的。这可以分为两种不同的情况。
情况1:在源代码中键入的字符串文字,例如。
情况2:通过标准输入流输入的字符串(在这种情况下为)。
这两种情况不一定以相同的方式存储字符串。我知道Unicode是一个字符集,UTF-8是一种编码方式,所以我想知道字符串文字是否在存储在内存时被编码,如果是,那么是如何编码的。
另外,如果有人知道如何自动识别当前终端使用的编码方式,那就太好了。
问候, Patrik
编辑
我收到了一些评论,尽管其中一些很好,但并不完全与问题相关。这意味着问题可能需要一些澄清。该问题可以看作是一个相当模糊的问题的概括:
“我能假设字符串文字以它们的Unicode代码点存储在内存中吗?”
这个问题的表述很差,至少有两个原因。首先,它对字符串文字的存储方式做出了假设(以它们的Unicode代码点)。这意味着答案必须涉及Unicode,即使这种关系可能完全没有意义。此外,这个问题是一个二选一的问题,如果答案是否定的,它将毫无帮助。
我也理解这可以通过将代码点转换为其整数等效项并打印来测试,但这将需要我针对整个Unicode字符集进行测试(这似乎是一种不合理的方法)。

2
如果您使用 utf8,则应该使用 stringcout 等而不是 w- 相关的函数。 - el.pescado - нет войне
2
问题在于字母 åäö 无法适应单个字符 - 这就是 utf8 编码的目的 - 将这些字母适应多个字符。最好将 length() 视为“字节数”,因为它已经失效了。请参见 http://utf8everywhere.org/ 和 http://programmers.stackexchange.com/questions/102205/should-utf-16-be-considered-harmful。 - el.pescado - нет войне
1
基本上,您不希望在源代码中出现非ASCII字符 - 很难预测它们最终会以什么方式出现在可执行二进制文件中。这取决于a)文本编辑器保存源文件的编码方式,b)编译器认为源文件所使用的编码方式,以及c)编译器认为可执行文件应该使用的编码方式。通过\xHH\uHHHH符号指定明确的代码点,或将这些字符串放入某种资源文件中,在运行时加载(后者还有助于本地化)。 - Igor Tandetnik
@IgorTandetnik 我理解并且同意非ASCII字符会带来麻烦。然而(如你所知),有时候“我想要”和“我需要”的东西可能不同:)。在瑞典,我们即便在电脑上做很多事情也是用瑞典语。我猜代码点可能已经存在了,问题更多的是如何让它与其他内容相配合。我以后源代码中不会有实际的字母。我猜这些字母将通过输入输入(例如第二个示例)输入到程序中。那么最有趣的是字符串如何以(w)cin读取并存储在内存中(假设cin使用正确的编码)。 - patrik
请阅读这篇文章,然后再重新审视你的问题。 - n. m.
显示剩余4条评论
2个回答

2

首先,文件被解释为一系列字符的方式是由实现定义的。您需要查阅编译器文档以确定这一点。

其次,使用的字符集也是由实现定义的。因此,您也需要咨询编译器来获取相关信息。

当您插入非ASCII字符(在使用ASCII时也可能出现)时,可能会发生的情况是编译器会以不同的方式解释它们。您需要检查不同的编译器是否可以处理相同的编码,最有可能可移植工作的源编码将是UTF-8。

此外,您最好使用UTF-8编码的文本来编写大部分程序(只有在需要处理字符串的API附近,才需要以这种方式处理字符串)。

总之,请确保您的编译器原样存储字符串文字,并使用普通(窄)字符串,并使用保存为UTF-8编码的编辑器。


0
这个主题在这里的 string_literal 页面上有很好的背景介绍。

https://en.cppreference.com/w/cpp/language/string_literal

我看到这个问题并不是关于字节和编码存储的问题,而是关于它们在内存中的位置,也就是在应用程序的静态内存中:
字符串字面量具有静态存储期,因此在程序的生命周期内存在于内存中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接