【发布时间】:2010-10-22 00:30:48
【问题描述】:
C 枚举声明中是否需要最后一个逗号?
即VAL3 后面的逗号是必需的吗?
enum { Val1, Val2, Val3, } someEnum;
将其放入/取出是否有任何副作用
谢谢
【问题讨论】:
-
在标准 C89 中,最后一个逗号被明确禁止。在 C99 中,他们允许这样做。保留它的副作用是它不能被严格的 C89 编译器编译。
C 枚举声明中是否需要最后一个逗号?
即VAL3 后面的逗号是必需的吗?
enum { Val1, Val2, Val3, } someEnum;
将其放入/取出是否有任何副作用
谢谢
【问题讨论】:
这不是必需的。 C99 的6.7.2.2 部分将语法列为:
enum-specifier:
enum identifieropt { enumerator-list }
enum identifieropt { enumerator-list , }
enum identifier
enumerator-list:
enumerator
enumerator-list , enumerator
enumerator:
enumeration-constant
enumeration-constant = constant-expression
注意enum-specifier 的前两种形式,一种带有尾随逗号,另一种没有。
我发现使用它的一个优点是:
enum {
Val1,
Val2,
Val3,
} someEnum;
如果您想添加(例如)Val4 和 Val5,您只需复制并粘贴 Val3 行,无需担心调整逗号。
还可以简化自动代码生成器,这样它们就不必对最终值进行特殊处理。他们可以只输出每个值,后跟一个逗号。
这可以比作常见的 SQL:
select fld1, fld2 from tbl where 1=1 and fld1 > 8
在这种情况下,where 1=1 的存在只是为了让您不必在第一个子句之前放置 where 并在每个后续子句之前放置 and。您可以依赖 where 已经存在这一事实,并为您添加的所有内容使用 and。
有些人可能认为这有点懒惰,他们是对的,但这不一定是坏事 :-)
任何体面的 DBMS 查询优化器都应该能够在访问数据库表之前去除类似的常量子句。
【讨论】:
正如其他人所说,逗号不是必需的。但它在 C99 中是新的(在 C89 中是不允许的),并且在下一版本的 C++ 中也将被允许。
另一个基本原理是区分“长度”枚举器和普通枚举器:
enum Items {
A,
B,
C,
LENGTH
};
现在,您可以在编码准则中输入枚举中的最后一项应该应用逗号,但如果它是“长度”项,则不是 - 它只是说明有多少项。
它还有助于自动生成项目(使用宏/预处理器),就像其他答案解释的那样。
【讨论】:
在标准 C89 中,最后一个逗号是不允许的。句号。
这是一个常见的扩展名;特别是,它得到了 GCC 的支持,但标准明确禁止它。
在标准 C99 中,为了与数组和结构初始化程序对称,最后一个逗号是允许的,这总是允许在最后一项上使用尾随逗号。
6.7.2.2 枚举说明符
语法
enum-specifier: enum identifieropt { enumerator-list } enum identifieropt { enumerator-list , } enum identifier
允许尾随逗号的主要优点是它允许更轻松地机器生成(C 源代码)代码 - 您不必为初始值设定项列表中的最后一个(或者,也许是第一个)项目编写特殊情况代码.因此,像 Yacc 和 Lex 这样的程序,仅举两个例子,可以稍微简单一些。
【讨论】:
不,这不是必需的。原因是,如果您不必担心逗号是否存在,它可以更轻松地剪切和粘贴代码。
【讨论】:
enum 定义或数组初始值设定项中的尾随 , 是可选的,但非常有用,尤其是在跨越多行的列表中。由于对称性的原因,自 C99 起允许使用,因为它为每个项目赋予所有行相同的结构:
enum DAY {
MON = 1,
TUE,
WED,
THU,
FRI,
SAT,
SUN,
};
它可以更轻松地使用脚本生成数组内容,并避免向数组添加额外元素但忘记添加逗号可能会被忽视的容易出错的情况:
const char *osnames[] = {
"CP/M",
"MS/DOS",
"Windows"
}
添加额外的项目:
const char *osnames[] = {
"CP/M",
"MS/DOS",
"Windows"
"Linux",
"OS/X"
};
注意列表中间缺少的逗号:编译器将第三个字符串解析为"WindowsLinux",并且该错误不会产生语法错误。
每行都有尾随,,在不修改其他行的情况下添加和删除项目要容易得多。如果像下面的例子那样有条件地编译行会更有用:
const char *osnames[] = {
"CP/M",
"MS/DOS",
"Windows",
#ifdef __UNIX__
"Linux",
"OS/X",
#endif
};
【讨论】:
不,它不是必需的 - 事实上我会说有它有不好的风格。
【讨论】:
如果说你使用宏,它是可选且有用的,例如
#ifdef _FLAG
#define OPTS opt_four, opt_five,
#else
#define OPTS // none
#endif
enum {
opt_one,
opt_two,
opt_three,
OPTS
};
【讨论】:
如前所述,它不是必需的。支持尾随逗号的原因是它(假设项目按一行排列)它允许您使用剪切/粘贴或拖放方便地重新排列枚举中项目的顺序,它还允许您注释掉最后一项而不产生语法错误。省略尾随逗号是合法的,但会失去这些代码维护优势。
我忘记了,但尼克说的很对。我也利用了带有编译器指令的尾随逗号。没有它,条件代码会更加混乱和难以阅读。
【讨论】:
【讨论】:
不,它不是必需的,为了代码清晰应该省略。它的存在/不存在没有影响。
【讨论】:
其他答案提到了它,但我只想强调在符合标准的 C89 和 C++ 中不允许使用尾随逗号,这使得它成为旧的或不常见的编译器的可移植性问题。这是一个有用的链接,可以解释这个问题和许多其他 C/C++ 问题:http://david.tribble.com/text/cdiffs.htm#C99-enum-decl
【讨论】:
它不是必需的,事实上如果你添加一个编译器会抱怨。例如 Visual Studio 6。
逗号的一种用途是使用 c 宏创建枚举。
#define ELEMENT(x) x,
enum MyElements {
ELEMENT(a)
ELEMENT(b)
ELEMENT(c)
};
如果您需要对元素执行几项操作并且只想定义一次,则此模式很有用。有关这方面的更完整示例,您可以查看 libiconv 和 iconv 实用程序的代码。
【讨论】:
#define ALL_ELEMENTS(ELEMENT) ELEMENT(a) ELEMENT(b) ELEMENT(c)。然后,您可以在任何特定时间将 #define ELEMENT 设置为您需要的任何内容,然后调用 ALL_ELEMENTS 宏。