【问题标题】:Correct behavior for string literal concatenation (C++11 phase 6 of translation)字符串文字连接的正确行为(C++11 翻译的第 6 阶段)
【发布时间】:2017-01-04 09:35:47
【问题描述】:

我很确定 Visual C++ 2015 在这里有一个错误,但我不是 100% 确定。

代码:

// Encoding: UTF-8 with BOM (required by Visual C++).
#include <stdlib.h>

auto main()
    -> int
{
    auto const s = L""
        "???? is not in the Unicode BMP!";
    return s[0] > 256? EXIT_SUCCESS : EXIT_FAILURE;
}

g++ 的结果:

[H:\scratchpad\simple_text_io] > g++ --版本 |找到“++” g++ (i686-win32-dwarf-rev1, 由 MinGW-W64 项目构建) 6.2.0 [H:\scratchpad\simple_text_io] > g++ compiler_bug_demo.cpp [H:\scratchpad\simple_text_io] > 运行 进程退出代码 = 0。 [H:\scratchpad\simple_text_io] > _

Visual C++ 的结果:

[H:\scratchpad\simple_text_io] > cl /nologo- 2>&1 |找到“++” Microsoft (R) C/C++ 优化编译器版本 19.00.23026 for x86 [H:\scratchpad\simple_text_io] > cl compiler_bug_demo.cpp /Feb compiler_bug_demo.cpp compiler_bug_demo.cpp(8): 警告 C4566: 由通用字符名 '\U00010437' 表示的字符不能在当前代码页中表示 (1252) [H:\scratchpad\simple_text_io] > 运行 b 进程退出代码 = 1。 [H:\scratchpad\simple_text_io] > _

是否涉及任何 UB,如果没有,哪个编译器行为正确?

附录:

如果使用小写希腊语 PI“π”(在 BMP 中 ),则两个编译器的行为都不会改变,因此这似乎无关紧要。

【问题讨论】:

  • 我正要说“VC++ 是错误的,因为 §2.14.5,第 13 项”,但围绕字符集的规则总是让我感到困惑。
  • VS 2015 update 3 (Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24213.1 for x86) 编译这个没有错误或警告;我将文件保存在 Emacs 的 utf-8-unix 编码系统中。你具体有哪个版本的VS?
  • @legends2k:问题中的示例列出了版本。
  • 它有编译器的版本,是的,但没有 Visual Studio 的版本。更新2、3,或者没有任何更新等
  • 哦。我很确定我从未安装过更新 3,因为他们内置了用于窥探的基础设施。这让我非常恼火。但是,每次过去,自 1990 年代初以来,我总是对微软的一些半不诚实的行为感到恼火。我只需要让它散发出来。但无论如何,重要的是编译器版本和构建,而且仅此而已。这包含在较大的版本号中。

标签: c++ visual-c++ g++


【解决方案1】:

来自[lex.string]

  1. 在翻译阶段 6 中,连接相邻的字符串文字。如果两个字符串文字具有相同的编码前缀,则生成的串联字符串文字具有该编码前缀。 如果一个字符串文字没有编码前缀,则将其视为与另一个操作数具有相同编码前缀的字符串文字。 如果 UTF-8 字符串文字标记与宽字符串文字相邻令牌,程序格式错误。任何其他 连接由实现定义的行为有条件地支持。 [注意:此连接是一种解释,而不是转换。因为口译发生在翻译阶段 6(之后 文字中的每个字符都已转换为相应字符集中的值),字符串文字的初始原始性对连接的解释或格式正确没有影响。 -结尾 note ] 表 8 提供了一些有效连接的示例。

所以这里没有 UB,但是翻译的第 5 阶段可能已经改变了某些字符的值:

  1. 每个源字符集成员在一个字符文字或一个字符串文字,以及每个转义序列和一个字符中的通用字符名称文字或非原始字符串文字,转换为执行字符集的相应成员,如果没有相应的成员,则转换为实现定义的成员,而不是 null(宽)字符。

【讨论】:

  • 是的,我不清楚第 5 阶段的事情。此时所有基本源字符集字符都已转换为(有效地)Unicode,但是否还有“源字符集”字符不在“基本源字符集”中? g++ 和 Visual C++ 之间的一个区别是 g++ 默认使用 UTF-8 作为其执行字符集,而 Visual C++ 默认使用 Windows ANSI(在我的例子中是代码页 1252)。但是这样的翻译通常会对宽字符串文字造成严重破坏!
  • @Cheersandhth.-Alf 不限制实现他们支持什么和不支持什么可能是故意含糊不清的。例如,您可以使用 16 位宽字符的编译器来忽略不是来自 BMP 的字符。 (这可能就是这里发生的事情)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-17
  • 1970-01-01
  • 2013-06-25
  • 1970-01-01
  • 2018-05-09
相关资源
最近更新 更多