【问题标题】:How does string work with non-ascii symbols while char does not?string 如何与非 ascii 符号一起工作,而 char 不?
【发布时间】:2014-06-10 15:30:31
【问题描述】:

我知道 C++ 中的char 只是一个整数类型,它将 ASCII 符号存储为范围从 0 到 127 的数字。斯堪的纳维亚字母 'æ'、'ø' 和 'å' 不在 128 个符号中ASCII 表。

所以很自然,当我尝试char ch1 = 'ø' 时,我得到一个编译器错误,但是string str = "øæå" 工作正常,即使一个字符串使用了chars right?

string 是否会以某种方式切换到 Unicode?​​p>

【问题讨论】:

  • 你应该指定你得到的什么错误。
  • 您可以使用明确的char ch1 = u'ø'char ch1 = U'ø' 解决编译器错误

标签: c++ string character-encoding char non-ascii-characters


【解决方案1】:

在C++中有源字符集执行字符集。源字符集是您可以在源代码中使用的字符集;但这不必与运行时可用的字符一致。

如果您在源代码中使用不在源字符集中的字符会发生什么,这是由实现定义的。显然'ø' 不在编译器的源字符集中,否则不会出错;这意味着您的编译器文档应该包含对这两个代码示例的作用的解释。可能您会发现str 中确实有某种字节序列,它们形成了一个字符串。

为避免这种情况,您可以使用字符文字而不是在源代码中嵌入字符,在本例中为 '\xF8'。如果还需要使用不在执行字符集中的字符,可以使用wchar_twstring

【讨论】:

  • "显然 'ø' 不在编译器的源字符集中,否则不会出错;"这不一定是真的。在某些情况下,规范确实准确描述了发生的情况,例如当执行编码中确实存在字符但不是由单个数值表示时(例如,多字节编码)。
  • wchar_t 字符和字符串文字使用“宽执行字符集”,它可能与常规执行字符集一样受到限制。但真正的编译器应该支持各种 Unicode 编码作为执行字符集。
  • 您也可以改用u'ø'U'ø'
  • @Cœur 编译器不需要支持该功能
【解决方案2】:

来自源代码char c = 'ø';

source_file.cpp:2:12: error: character too large for enclosing character literal type
  char c = '<U+00F8>';
           ^

这里发生的情况是编译器正在从源代码编码转换字符,并确定没有使用适合单个char 的执行编码表示该字符。 (注意这个错误与c的初始化无关,任何这样的字符文字都会发生。examples

但是,当您将此类字符放入字符串文字而不是字符文字时,编译器从源编码到执行编码的转换非常乐意在执行编码为多字节时使用字符的多字节表示形式。字节,比如UTF-8就是。

为了更好地理解编译器在这方面的工作,您应该首先阅读 C++ 标准中的第 2.3 [lex.charsets]、2.14.3 [lex.ccon] 和 2.14.5 [lex.string] 条款。

【讨论】:

  • 那么为什么在clang上会发生这种情况但与gcc一起使用。 clang 允许其他多字节字符,例如 'aa'
  • Clang 读取单个字符并将其视为 C++ 语法中的单个 c-char,这意味着结果不能是 多字符文字。 Gcc 将在 UTF-8 中编码为多个字节的单个代码点视为序列 c-chars。甚至可能有一种方法可以解释 gcc 的行为,使其在技术上符合规范(尽管由于规范中将 UCN 指定为单个 c-char,因此这并不是很明显)。我认为 clang 的行为更好(并且符合规范)。
【解决方案3】:

这里可能发生的情况是您的源文件被编码为 UTF-8 或其他一些多字节字符编码,而编译器只是将其视为字节序列。单个char 只能是单个字节,但字符串完全可以满足所需的字节数。

【讨论】:

  • 如果编译器不处理源编码到执行编码转换,那么在字符文字中具有多字节源编码的字符通常会产生多字符而不是错误。这就是 gcc 所做的以及为什么使用 gcc 构建代码 std::cout &lt;&lt; std::hex &lt;&lt; 'ø'; 会打印“c3b8”。
  • @bames53 如果您尝试将其分配给char 变量,大于char 的字符文字将至少生成一个警告。您的示例回避了这种转换。
【解决方案4】:

C++ 的 ASCII 只有 128 个字符。 如果你想要'ø',它是(255)中的 ASCII-EXTENDED 248,它是 8 位(不是字符值),其中包括来自 ASCII 的 7 位。 你可以试试char ch1 ='\xD8';

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-03
    • 2016-06-05
    • 2011-09-06
    • 1970-01-01
    • 2014-03-29
    • 1970-01-01
    • 2021-01-26
    • 1970-01-01
    相关资源
    最近更新 更多