16

我在新的 C++ 标准中找到

2.11 Identifiers                  [lex.name]
identifier:
    identifier-nondigit
    identifier identifier-nondigit
    identifier digit
identifier-nondigit:
    nondigit
    universal-character-name
    other implementation-defined character

附加文本

标识符是任意长的字母和数字序列。标识符中的每个通用字符名称应指定一个字符,其在 ISO 10646 中的编码属于 E.1 中规定的范围之一。[...]

我不能完全理解这意味着什么。例如,从旧的标准中,我习惯于写一个“通用字符名称” \u89ab。但是在标识符中使用那些......?真的吗?

新标准是否对 Unicode 更开放?而且我没有提到新的Literal Types "uHello \u89ab thing"u32,我想我理解了那些。但:

  • (便携式)源代码可以采用任何 unicode 编码,如 UTF-8、UTF-16 或任何(如何定义)代码页?
  • 我可以\u1234在其中写一个标识符吗myfu\u1234ntion(无论出于何种目的)
  • 或者我可以使用 unicode 在 ICU 中定义的“字符名称”,即

    const auto x = "German Braunb\U{LOWERCASE LETTER A WITH DIARESIS}r."u32;
    

    甚至在源本身的标识符中?那将是一种享受......咳嗽......

我认为所有这些问题的答案是否定的,但我无法将其可靠地映射到标准中的措辞...... :-)

编辑:我发现“2.2 翻译阶段 [lex.phases]”,第 1 阶段:

如有必要,物理源文件字符以实现定义的方式映射到基本源字符集 [...]。接受的物理源文件字符集是实现定义的。[...] 任何不在基本源字符集 (2.3) 中的源文件字符都将替换为指定该字符的通用字符名称。(实现可以使用任何内部编码,只要在源文件中遇到的实际扩展字符,以及在源文件中表示为通用字符名称的相同扩展字符(即,使用 \uXXXX 表示法)是等效处理,除非此替换在原始字符串文字中恢复。)

通过阅读本文,我现在认为,编译器可以选择接受 UTF-8、UTF-16 或它希望的任何代码页(通过元信息或用户配置)。在第 1 阶段,它将其转换为 ASCII 形式(“基本源字符集”),然后将 Unicode 字符替换为其\uNNNN符号(或者编译器可以选择继续以它的 Unicode 表示形式工作,但必须确保它\uNNNN以相同的方式处理另一个。

你怎么看?

4

5 回答 5

13

新标准是否对 Unicode 更开放?

关于允许在标识符中使用通用字符名称,答案是否定的;早在 C99 和 C++98 中就允许在标识符中使用 UCN。然而,编译器直到最近才实现该特定要求。我认为 Clang 3.3 引入了对此的支持,并且 GCC 已经为此提供了一个实验性功能已有一段时间了。Herb Sutter 在他的 Build 2013 演讲“C++ 的未来”中也提到,这个特性也将在某个时候出现在 VC++ 中。(尽管 IIRC Herb 将其称为 C++11 功能;它实际上是 C++98 功能。)

预计不会使用 UCN 编写标识符。相反,预期的行为是使用源编码写入所需的字符。例如,源代码如下所示:

long pörk;

不是:

long p\u00F6rk;

然而,UCN 也可用于其他目的;并非所有编译器都必须接受相同的源编码,但现代编译器都支持某些编码方案,其中至少基本源字符具有相同的编码(也就是说,现代编译器都支持某些 ASCII 兼容编码)。

UCN 允许您仅使用基本字符编写源代码,但仍命名扩展字符。这在例如在源代码中编写字符串文字“°”时很有用,该源代码将被编译为 CP1252 和 UTF-8:

char const *degree_sign = "\u00b0";

这个字符串文字在多个编译器上被编码为适当的执行编码,即使源编码不同,只要编译器至少对基本字符共享相同的编码。

(便携式)源代码可以采用任何 unicode 编码,如 UTF-8、UTF-16 或任何(如何定义)代码页?

它不是标准要求的,但大多数编译器都会接受 UTF-8 源代码。Clang支持UTF-8 源(尽管它对字符和字符串文字中的非 UTF-8 数据有一些兼容性),gcc 允许指定源编码并包括对 UTF-8 的支持,VC++ 会猜测编码并且可以猜测UTF-8。

(更新:VS2015 现在提供了一个选项来强制源和执行字符集为 UTF-8。)

我可以在其中写一个带有 \u1234 的标识符吗 myfu\u1234ntion (无论出于何种目的)

是的,规范要求这样做,尽管正如我所说,并非所有编译器都实现了这一要求。

或者我可以使用 unicode 在 ICU 中定义的“字符名称”,即

const auto x = "German Braunb\U{LOWERCASE LETTER A WITH DIARESIS}r."u32;

不,您不能使用 Unicode 长名称。

甚至在源本身的标识符中?那将是一种享受……咳嗽……

如果编译器支持包含您想要的扩展字符的源代码编码,那么在源代码中按字面书写的字符必须与等效的 UCN 完全相同。所以是的,如果您使用支持 C++ 规范的这一要求的编译器,那么您可以直接在源代码中编写其源字符集中的任何字符,而无需编写 UCN。

于 2013-07-02T17:19:39.873 回答
3

我认为其目的是允许标识符中包含 Unicode 字符,例如:

long pöjk;
ostream* å;
于 2011-04-15T13:12:37.970 回答
2

我建议使用clang++而不是g++. Clang 被设计为与 GCC ( wikipedia-source ) 高度兼容,因此您很可能只需替换该命令。

我想在我的源代码中使用希腊符号。如果代码可读性是目标,那么使用(例如)αover似乎是合理的alpha。尤其是在较大的数学公式中使用时,它们可以在源代码中更容易阅读。

为此,这是一个最小的工作示例:

> cat /tmp/test.cpp
#include <iostream>

int main()
{
    int α = 10;
    std::cout << "α = " << α << std::endl;
    return 0;
}
> clang++ /tmp/test.cpp -o /tmp/test
> /tmp/test 
α = 10
于 2016-09-25T15:41:51.453 回答
1

这篇文章https://www.securecoding.cert.org/confluence/display/seccode/PRE30-C.+Do+not+create+a+universal+character+name+through+concatenationint \u0401;符合代码兼容的思想,虽然它基于 C99,而不是 C++0x。

于 2011-08-02T16:49:16.020 回答
1

目前的 gcc 版本(到目前为止最高版本为 5.2)仅支持 ASCII 并且在某些情况下支持 EBCDIC 输入文件。因此,标识符中的 unicode 字符必须使用 ASCII 编码文件中的 \uXXXX 和 \UXXXXXXXX 转义序列来表示。虽然在 EBCDIC 编码的输入文件中可以将 unicode 字符表示为 ??/uXXXX 和 ??/UXXXXXXX,但我尚未对此进行测试。无论如何,只要安装了最新版本的 iconv,一个简单的 cpp 单行补丁就可以直接读取 UTF-8 输入。详情在

https://www.raspberrypi.org/forums/viewtopic.php?p=802657

并且可以通过补丁进行总结

diff -cNr gcc-5.2.0/libcpp/charset.c gcc-5.2.0-ejo/libcpp/charset.c
*** gcc-5.2.0/libcpp/charset.c  Mon Jan  5 04:33:28 2015
--- gcc-5.2.0-ejo/libcpp/charset.c  Wed Aug 12 14:34:23 2015
***************
*** 1711,1717 ****
    struct _cpp_strbuf to;
    unsigned char *buffer;

!   input_cset = init_iconv_desc (pfile, SOURCE_CHARSET, input_charset);
    if (input_cset.func == convert_no_conversion)
      {
        to.text = input;
--- 1711,1717 ----
    struct _cpp_strbuf to;
    unsigned char *buffer;

!   input_cset = init_iconv_desc (pfile, "C99", input_charset);
    if (input_cset.func == convert_no_conversion)
      {
        to.text = input;
于 2015-08-15T00:20:17.430 回答