为什么未为C ++ 14数字分隔符选择空格字符?


69

从C ++ 14开始,由于n3781(它本身不能回答这个问题),我们可以编写如下代码:

const int x = 1'234; // one thousand two hundred and thirty four

目的是改进这样的代码:

const int y = 100000000;

并使其更具可读性。

下划线(_)字符已经由用户定义的文本采取了C ++ 11,和逗号(,)的本地化问题-许多欧洲国家令人困惑以此作为小数点分隔符-和冲突与逗号操作,虽然我做的想知道允许使用可能破坏了哪些实际代码1,234,567

无论如何,更好的解决方案似乎是空格字符:

const int z = 1 000 000;

这些相邻的数字文字标记可以和字符串文字一样由预处理器连接:

const char x[5] = "a" "bc" "d";

相反,我们得到撇号('),我所知道的任何书写系统都没有使用它作为数字分隔符。

是否存在选择撇号而不是简单空格的原因?


之所以感到莫名其妙,是因为所有这些语言在文本内都保持着逗号的概念,即“分开”原本原子的句子,并用句号“终结”该句子-至少对我而言,这与逗号“分解”数字的整数部分,并用句号“终止”数字以准备小数输入。


21
关于逗号,是不是逗号运算符,而不是本地化问题?
本杰明·林德利

45
@LightnessRacesinOrbit:我认为没有人打算改变的含义int a[] = {123,000,000}。至于逗号与句点之间的区别,请注意,它们在文本和数字上都已相当标准化。
MSalters

4
除了技术要点外,您还说我知道的任何书写系统都不会使用撇号(')作为数字分隔符。有一个国家使用撇号作为数字分隔符:瑞士。在作者更喜欢它的情况下,或者在一个点/逗号会引起混淆的情况下,我也看到了它,因为它们在国际上使用的方式有所不同。
dlrlc 2015年

9
如果这样能让您好起来,我是欧洲人,这是由于美国制造了许多产品(计算器等),这些产品使用逗号作为十进制值是-幸运的是-慢慢地变味了。我想说0.99现在比0.99更广泛地使用;使用逗号作为千位分隔符是闻所未闻的,就像使用点一样,我们只是不分隔它们(可能是因为现在1,234和1.234都表示小数)
Thomas Bonini 2015年

8
@BenjaminLindley我本来以为逗号问题可能是模棱两可的情况int foo(int);int foo(int,int); foo(1,000);
立方

Answers:


40

先前有一篇论文n3499,它告诉我们,尽管Bjarne本人建议使用空格作为分隔符:

尽管此方法与一种常见的排版样式一致,但仍存在一些兼容性问题。

  • 它与pp-number的语法不匹配,并且至少需要扩展该语法。
  • 更重要的是,当[af]范围内的十六进制数字跟随一个空格时,在语法上会有些歧义。预处理器将不知道是否在空格之后开始执行符号替换。
  • 可能会使捕获“单词”的编辑工具的可靠性降低。

我想以下示例是指出的主要问题:

const int x = 0x123 a;

尽管在我看来,这个理由还很薄弱。我仍然想不出一个打破现实的例子。

“编辑工具”的原理甚至更糟,因为1'234基本上破坏了人类已知的每个语法突出显示(例如,上述问题本身中Markdown所使用的语法!),并使所述突出显示的更新版本更加难以实现。

不管是好是坏,这都是导致使用撇号的理由。


4
@aschepler:如果我是地球总统,那么“文字”可能会在其作品中包含一个空间,从而形成0x123 a45一个单一的,尽管有多个令牌的文字。您能想到一个场景,在a45这里不希望将其解释为整数文字的一部分吗?之前没有运算符或其他任何东西,那么它还能是什么?
Lightness Races in Orbit 2015年

15
#define abc + 1const int x = 0x123 abc;
TC

2
@TC宏在第4阶段进行了扩展,字符串文字在第6阶段进行了连接。我希望在第6阶段也可以进行“数字文字连接”,从而保持示例代码的行为并且不会破坏任何内容。
Lightness Races in Orbit 2015年

9
@LightnessRacesinOrbit我不确定是否那么简单。要允许宏替换,您必须将其解析abc为一个标识符,但是随后您必须指定pp-number和一个标识符的某种串联,这很奇怪。此外,显然还存在与破坏Objective-C有关的重大问题
TC

1
@supercat:这是糟糕的代码,我宁愿我们没有对其进行优化; p
轨道轻便竞赛

16

不使用空格的明显原因是换行符也是空格,并且C ++平等地对待所有空格。另外,我不知道有任何语言接受任意空格作为分隔符。

大概可以使用Unicode 0xA0(不间断空格),它是排版时使用最广泛的解决方案。但是,我看到了两个问题:首先,它不在基本字符集中,其次,在视觉上没有区别。仅通过在普通编辑器中查看文本就看不到它不是空格。

除此之外,没有太多选择。您不能使用逗号,因为它已经是合法令牌(和类似1,234当前合法的C ++,含义为234)。并且在可能以法律代码出现的情况下,例如a[1,234]。尽管我无法想象实际使用此代码的任何实际代码,但有一个基本规则,即无论多么荒谬的法律程序都不应默默更改语义。

类似的考虑也意味着_不能使用。如果有 #define _234 * 2,则a[1_234]则将默默更改代码的含义。

我不能说我对的选择感到特别满意',但是它确实具有在欧洲大陆使用的优势,至少在某些类型的文本中也是如此。(例如,我似乎记得曾用德语看过它,尽管在典型的运行文本中,德语像大多数其他语言一样会使用点或不间断的空格。但是也许是瑞士德语。)'解析的问题; 该顺序'1'已经是合法的'123'。所以类似的东西1'234可能是1,后跟一个字符常量的开头;我不确定您必须提前多久才能做出决定。没有合法的C ++序列,其中可以在整数常量后跟一个字符常量,因此打破合法代码没有问题,但这意味着词法扫描突然变得非常依赖于上下文。

(关于您的评论:选择十进制或千位分隔符没有逻辑。例如,十进制分隔符肯定不是句号。它们只是任意约定。)


1
“换行也是空白”。对不起,如果我被愚蠢地听到,那为什么呢?:)
gsamaras

2
@ G.Samaras:C将“空白”定义为“ ...空格,水平制表符,换行符,垂直制表符和换页符”,这完全是常规的。
Lightness Races in Orbit 2015年

15
@LightnessRacesinOrbit甚至void f(int); void f(int, int); f(12,345);
TC

1
@CraigMcQueen这是一个多字符文字。由于实现定义的性质,它不是很有用。
milleniumbug

1
@ G.Samaras因为C ++不面向行。换行符与该语言中的任何其他空格完全相同。
James Kanze 2015年

10

wiki上,我们有一个很好的例子:

auto floating_point_literal = 0.000'015'3;

在这里,我们有一个.运算符,然后如果要遇到另一个运算符,我的眼睛将等待可见的内容,例如逗号或类似内容,而不是空白。

因此,撇号在这里比空白要好得多。

有了空格,它将是

auto floating_point_literal = 0.000 015 3;

这与撇号的感觉不一样。


按照阿尔伯特·伦肖Albert Renshaw)的回答,我认为撇号比《轻度种族在轨道》中提出的空间更清晰。

type a = 1'000'000'000'000'000'544'445'555;
type a = 1 000 000 000 000 000 544 445 555;

空格用于很多事情,例如OP提到的字符串连接,而不是撇号,在这种情况下,空格使清楚的人用于分隔数字。

当代码行变得很多时,我认为这将提高可读性,但是我怀疑那是他们选择它的原因。


关于空间,可能值得看看这个C问题,它说:

该语言不允许int i = 10 000;(整数文字是一个标记,中间的空格将其分成两个标记),但是通过将初始化器表示为一个计算文字的表达式,通常不会产生任何费用:

int i = 10 * 1000; /* ten thousand */


通常,您要表达的长数字不会以全零结尾,在这种情况下,您的10*1000示例将无法正常工作。
Mark Ransom

@MarkRansom这是我链接的答案中粘贴的示例。您认为我应该修改它?
gsamaras

3
我想,您知道该论文有关空白超载的发布日期(特别是月份和日期,而不是年份),对吗?
本杰明·林德利

是的,不是那么现代,我将编辑@BenjaminLindley。
gsamaras

10
它的现代性不是问题。仔细调查一下。如果该日期在您所在的地区没有重要意义,请谷歌搜索。
本杰明·林德利

9

的确,我认为:

if (a == 1 1 1 1 1) ...

因此数字可以合并而没有真正的歧义,但是十六进制数字呢?

0 x 1 a B 2 3

这样做无法消除拼写错误(通常我们应该看到一个错误)


好吧,简单。现在它将是有效代码,而不是错误。拼写错误仍然可以产生有效的代码,如果您的“语言”由多个单词组成,则绝对没有办法防止这种情况。
立方

5

我认为这是因为在编写代码时,如果到达“行”(屏幕的宽度)的末尾,则会出现自动换行符(或“自动换行”)。这将导致您的int被分成两半,其中一半将出现在第一行中,后半部分出现在第二行中...这样,如果发生,它们将保持在一起word-wrap


3
我不是C ++设计委员会的成员,但是从我收集的信息来看,此类担忧通常不会影响决策。
templatetypedef

4
我不认为这是原因,但这是我没有考虑过的有趣原因。在更多的人的答案中开放更多的想法:)
轨道轻轨赛

@LightnessRacesinOrbit另外,它还可能防止代码编译器忽略数字中断。空格会被剥夺,这些可能会留下。但这是任何人都在乎这个哈哈的愚蠢可能性。
艾伯特·伦肖

@AlbertRenshaw:我不关注吗?
Lightness Races in Orbit 2015年

1
float floating_point_literal = 0.0000153;   /* C, C++*/

auto floating_point_literal = 0.0000153;    // C++11

auto floating_point_literal = 0.000'015'3;  // C++14

发表评论不会造成伤害:

/*  0. 0000 1530 */ 
float floating_point_literal = 0.00001530; 

二进制字符串可能很难解析:

long bytecode = 0b1111011010011001; /* gcc , clang */  

long bytecode = 0b1111'0110'1001'1001;  //C++14
// 0b 1111 0110 1001 1001  would be better, really.
// It is how humans think.

需要考虑的宏:

#define B(W,X,Y,Z)    (0b##W##X##Y##Z)
#define HEX(W,X,Y,Z)  (0x##W##X##Y##Z)
#define OCT(O)        (0##O)



long z = B(1001, 1001, 1020, 1032 ); 

// result :  long z = (0b1001100110201032);

 long h = OCT( 35); 

// result :  long h  = (035); // 35_oct => 29_dec

 long h = HEX( FF, A6, 3B, D0 ); 

// result :  long h  = (0xFFA6BD0);

2
这不能回答问题。
Zereges

3
哦,是的,发表评论确实有害。一个问题是,无论现在还是将来,评论都可能是错误的。另一个是重复性会阻碍可读性并且容易出错。
Deduplicator

@Deduplicator在这种情况下,发现错误的注释非常容易(注释没有添加含义,只是重新格式化了其下方的信息)。
Lightness Races in Orbit Race '18

当然,在这种情况下很容易发现。如果您转移了注意力,可以尝试这样做。
Deduplicator

-1

它与语言的解析方式有关。对于编译器作者来说,很难重写其产品以接受以空格分隔的文字。

另外,我认为用空格分隔数字并不常见。我已经知道,即使在不同的国家,也总是非空白字符。


1
无论如何,他们不得不改变他们的解析器。
轨道轻盈赛

@BoundaryImposition恐怕您听不懂。空格已经在语言中具有含义。一个基本的。将12'345'678(数字分隔符)更改为二进制形式与不使用数字分隔符大致相同。编译器作者需要花费相同的精力。而重新定义令牌化系统本身将是困难的。加上空格分隔的数字看起来很难看。
iPherian

2
我可以向您保证我确实了解。不需要“重新定义”“令牌系统”。例如,考虑字符串文字串联,它已经可以正常工作了。
轨道轻度比赛

1
空格仅具有“基本的”含义,因为它可以防止两个连续的字符成为同一标记的一部分。正如OP所提到的,可以将其简单地放入“连接相邻字符串文字”预处理程序通道中。(主)解析器甚至都不会看到它。
Sneftel

1
恐怕您过于夸大了令牌生成器。你可以要么是作为为字符串文字,为此,级联发生在翻译阶段6,即6阶段完成,["foobar"] ["frob"]变成["foobarfrob]。或者可以将标记化程序扩展为吸收空格: decimal_literal ::= [1-9][0-9]+[uU]?(l|L|ll|LL)?变为decimal_literal ::= [1-9][ 0-9]+[uU]?(l|L|ll|LL)?,在这种情况下,文字必须稍后进行规范化。基本上与的操作模式相同'。不知道您真正想说什么:|
塞巴斯蒂安·马赫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.