int a [] = {1,2,}; 允许使用怪异的逗号。 有什么特殊原因吗?

本文翻译自:int a[] = {1,2,}; Weird comma allowed. Any particular reason?

Maybe I am not from this planet, but it would seem to me that the following should be a syntax error: 也许我不是来自这个星球,但是在我看来,以下内容应该是语法错误:

int a[] = {1,2,}; //extra comma in the end

But it's not. 但事实并非如此。 I was surprised when this code compiled on Visual Studio, but I have learnt not to trust MSVC compiler as far as C++ rules are concerned, so I checked the standard and it is allowed by the standard as well. 当在Visual Studio中编译的代码我很惊讶,但我已经学会了不信任MSVC编译器尽可能C ++的规则而言,所以我检查的标准,它标准允许为好。 You can see 8.5.1 for the grammar rules if you don't believe me. 如果您不相信我,可以查看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 . 例如,不允许在函数调用参数列表的末尾(当函数采用... )使用多余的逗号, 这是正常现象

So, again, is there any particular reason this redundant comma is explicitly allowed? 因此,再次,是否有任何特定原因明确允许使用此冗余逗号?


#1楼

参考:https://stackoom.com/question/TYIm/int-a-允许使用怪异的逗号-有什么特殊原因吗


#2楼

This is allowed to protect from mistakes caused by moving elements around in a long list. 这样可以防止因在长列表中四处移动元素而导致的错误。

For example, let's assume we have a code looking like this. 例如,假设我们有一个看起来像这样的代码。

#include <iostream>
#include <string>
#include <cstddef>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof *(array))
int main() {
    std::string messages[] = {
        "Stack Overflow",
        "Super User",
        "Server Fault"
    };
    size_t i;
    for (i = 0; i < ARRAY_SIZE(messages); i++) {
        std::cout << messages[i] << std::endl;
    }
}

And it's great, as it shows the original trilogy of Stack Exchange sites. 它很棒,因为它显示了Stack Exchange网站的原始三部曲。

Stack Overflow
Super User
Server Fault

But there is one problem with it. 但是,这有一个问题。 You see, the footer on this website shows Server Fault before Super User. 您会看到,该网站上的页脚在超级用户之前显示服务器故障。 Better fix that before anyone notices. 最好在所有人注意到之前解决此问题。

#include <iostream>
#include <string>
#include <cstddef>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof *(array))
int main() {
    std::string messages[] = {
        "Stack Overflow",
        "Server Fault"
        "Super User",
    };
    size_t i;
    for (i = 0; i < ARRAY_SIZE(messages); i++) {
        std::cout << messages[i] << std::endl;
    }
}

After all, moving lines around couldn't be that hard, could it be? 毕竟,绕线移动并不难,不是吗?

Stack Overflow
Server FaultSuper User

I know, there is no website called "Server FaultSuper User", but our compiler claims it exists. 我知道,没有名为“ Server FaultSuper User”的网站,但是我们的编译器声称它存在。 Now, the issue is that C has a string concatenation feature, which allows you to write two double quoted strings and concatenate them using nothing (similar issue can also happen with integers, as - sign has multiple meanings). 现在,问题在于C具有字符串连接功能,该功能使您可以编写两个双引号字符串并不使用它们进行连接(整数也可能发生类似的问题,因为-符号具有多种含义)。

Now what if the original array had an useless comma at end? 现在,如果原始数组结尾处没有逗号,该怎么办? Well, the lines would be moved around, but such bug wouldn't have happened. 好吧,这些线会四处移动,但是这种错误不会发生。 It's easy to miss something as small as a comma. 很容易错过像逗号这样的小东西。 If you remember to put a comma after every array element, such bug just cannot happen. 如果您记得在每个数组元素后都添加逗号,那么这种错误就不会发生。 You wouldn't want to waste four hours debugging something, until you would find the comma is the cause of your problems . 发现逗号是造成问题的原因之前,您不会希望花费四个小时来调试某些内容


#3楼

Like many things, the trailing comma in an array initializer is one of the things C++ inherited from C (and will have to support for ever). 像许多事物一样,数组初始化程序中的尾部逗号是C ++从C继承的事物之一(并且必须永远支持)。 A view totally different from those placed here is mentioned in the book "Deep C secrets" . “ Deep C的秘密”一书中提到了与此处完全不同的观点

Therein after an example with more than one "comma paradoxes" : 在其中有多个“逗号悖论”的示例之后:

char *available_resources[] = {
"color monitor"           ,
"big disk"                ,
"Cray"                      /* whoa! no comma! */
"on-line drawing routines",
"mouse"                   ,
"keyboard"                ,
"power cables"            , /* and what's this extra comma? */
};

we read : 我们读 :

...that trailing comma after the final initializer is not a typo, but a blip in the syntax carried over from aboriginal C . ...最后的初始值设定项后的逗号不是错别字,而是从原住民C继承过来的语法上的错误。 Its presence or absence is allowed but has no significance . 允许存在或不存在它,但没有意义 The justification claimed in the ANSI C rationale is that it makes automated generation of C easier. ANSI C基本原理要求的理由是,它使C的自动生成更加容易。 The claim would be more credible if trailing commas were permitted in every comma-sepa-rated list , such as in enum declarations, or multiple variable declarators in a single declaration. 如果在每个逗号分隔的列表 (例如枚举声明中)或单个声明中的多个变量声明符中都允许使用尾部逗号,则该声明将更加可信 They are not. 他们不是。

... to me this makes more sense ...对我来说更有意义


#4楼

I am surprised after all this time no one has quoted the Annotated C++ Reference Manual ( ARM ), it says the following about [dcl.init] with emphasis mine: 一直以来,没有人引用Annotated C ++ Reference ManualARM ),它使我很惊讶,它对[dcl.init]的强调如下:

There are clearly too many notations for initializations, but each seems to serve a particular style of use well. 显然有太多用于初始化的符号,但是每种符号似乎都很好地服务于特定的使用风格。 The ={initializer_list,opt} notation was inherited from C and serves well for the initialization of data structures and arrays. = {initializer_list,opt}表示法是从C继承的,非常适合于数据结构和数组的初始化。 [...] [...]

although the grammar has evolved since ARM was written the origin remains. 尽管自编写ARM以来语法已经发展,但起源仍然存在。

and we can go to the C99 rationale to see why this was allowed in C and it says: 我们可以参考C99的原理 ,了解为什么在C语言中允许这样做,并说:

K&R allows a trailing comma in an initializer at the end of an initializer-list. K&R允许在初始化器列表末尾的初始化器中使用逗号。 The Standard has retained this syntax, since it provides flexibility in adding or deleting members from an initializer list, and simplifies machine generation of such lists. 该标准保留了这种语法,因为它提供了在初始化器列表中添加或删除成员的灵活性,并简化了此类列表的机器生成。


#5楼

I see one use case that was not mentioned in other answers, our favorite Macros: 我看到其他答案中没有提到的一种用例,即我们最喜欢的宏:

int a [] = {
#ifdef A
    1, //this can be last if B and C is undefined
#endif
#ifdef B
    2,
#endif
#ifdef C
    3,
#endif
};

Adding macros to handle last , would be big pain. 添加宏以处理last ,将是一件很痛苦的事情。 With this small change in syntax this is trivial to manage. 由于语法上的微小更改,这很容易管理。 And this is more important than machine generated code because is usually lot of easier to do it in Turing complete langue than very limited preprocesor. 这比机器生成的代码更重要,因为通常使用图灵完整语言比非常有限的前处理器要容易得多。


#6楼

It makes generating code easier as you only need to add one line and don't need to treat adding the last entry as if it's a special case. 它使生成代码更加容易,因为您只需要添加一行,而不必将添加最后一项视为特殊情况。 This is especially true when using macros to generate code. 使用宏生成代码时尤其如此。 There's a push to try to eliminate the need for macros from the language, but a lot of the language did evolve hand in hand with macros being available. 有一种尝试试图从语言中消除对宏的需求,但是许多语言确实与宏一起发展。 The extra comma allows macros such as the following to be defined and used: 多余的逗号允许定义和使用以下宏:

#define LIST_BEGIN int a[] = {
#define LIST_ENTRY(x) x,
#define LIST_END };

Usage: 用法:

LIST_BEGIN
   LIST_ENTRY(1)
   LIST_ENTRY(2)
LIST_END

That's a very simplified example, but often this pattern is used by macros for defining things such as dispatch, message, event or translation maps and tables. 这是一个非常简化的示例,但是宏通常使用此模式来定义诸如分发,消息,事件或转换映射和表之类的内容。 If a comma wasn't allowed at the end, we'd need a special: 如果最后不允许使用逗号,则需要特殊的:

#define LIST_LAST_ENTRY(x) x

and that would be very awkward to use. 而且使用起来会很尴尬。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值