也许我不是来自这个星球,但在我看来,以下应该是一个语法错误:
int a[] = {1,2,}; //extra comma in the end
但事实并非如此。当这段代码在Visual Studio上编译时,我很惊讶,但我已经学会了不相信MSVC编译器,就c++规则而言,所以我检查了标准,它也是标准允许的。如果你不相信的话,语法规则可以参考8.5.1。
Why is this allowed? This may be a stupid useless question but I want you to understand why I am asking. If it were a sub-case of a general grammar rule, I would understand - they decided not to make the general grammar any more difficult just to disallow a redundant comma at the end of an initializer list. But no, the additional comma is explicitly allowed. For example, it isn't allowed to have a redundant comma in the end of a function-call argument list (when the function takes ...), which is normal.
那么,有什么特别的原因,这个多余的逗号是明确允许的吗?
我很惊讶这么长时间以来没有人引用注解c++参考手册(ARM),它是这样描述[dcl. C]的。我的:
用于初始化的表示法显然太多了,但每种表示法似乎都适用于特定的使用风格。={initializer_list,opt}符号继承自C语言,可以很好地初始化数据结构和数组。[…]
尽管自ARM诞生以来语法一直在发展,但起源仍然存在。
我们可以查看C99的基本原理,看看为什么在C中允许这样做,它说:
类的初始化式中允许有一个尾随逗号
初始化器列表。标准保留了这个语法,因为它
提供从初始化式中添加或删除成员的灵活性
列表,并简化了此类列表的机器生成。
每个人都说添加/删除/生成行很容易,但这种语法真正的亮点是合并源文件。假设你有这样一个数组:
int ints[] = {
3,
9
};
假设您已经将这段代码签入存储库。
然后你的朋友编辑它,在结尾添加:
int ints[] = {
3,
9,
12
};
你同时编辑它,在开头加上:
int ints[] = {
1,
3,
9
};
从语义上讲,这些类型的操作(添加到开头,添加到结尾)应该是完全合并安全的,你的版本控制软件(最好是git)应该能够自动合并。遗憾的是,情况并非如此,因为你的版本在9后面没有逗号,而你朋友的版本有。然而,如果最初的版本后面有9,他们就会自动生成。
因此,我的经验法则是:如果列表跨越多行,则使用尾随逗号,如果列表在单行上,则不要使用尾随逗号。
它使生成源代码变得更容易,也使编写日后可以轻松扩展的代码变得更容易。考虑一下添加额外条目需要什么:
int a[] = {
1,
2,
3
};
... 您必须在现有行中添加逗号,并添加新行。与“3”后面已经有逗号的情况相比,你只需要添加一行。同样地,如果你想删除一行,你可以不用担心它是否是最后一行,你可以重新排序而不用用逗号。基本上,这意味着你对待线条的方式是一致的。
现在考虑生成代码。类似(伪代码):
output("int a[] = {");
for (int i = 0; i < items.length; i++) {
output("%s, ", items[i]);
}
output("};");
不需要担心您正在输出的当前项是第一个还是最后一个。更加简单。