这个枚举声明是否符合标准?

11

通常情况下,枚举是用于声明一组“常量整数”作为另一种类型,以表示某些东西。例如:

所以正常情况下,枚举是用来将“常量整数”分组并定义为另一种类型,以表示某个含义。

enum Color {RED=0, BLUE, YELLOW};

这很清楚。但最近我在代码中遇到了以下情况。这是嵌入式系统编译器中的一部分。

enum State {DISABLED=0, ENABLED=!DISABLED};

它运行得非常好。 它表现得像布尔类型。我的问题是,这个语法是否符合ANSI标准?

如果它符合标准,那么编译器为什么会在内部定义诸如_Bool之类的东西作为布尔表示,然后在C语言的stdbool.h中这样做:

#define bool _Bool
... // here goes definitions of true and false
代替
enum bool {false=0, true=!false};

哪一个更加干净整洁?


符合 ANSI 标准?这是我很久没有听到的短语了。 - Alan Stokes
@DawidPi C 和 C++ 是不同的编程语言,像这样微妙的问题几乎不可能得到一份涵盖两种语言的好答案。如果你真的想了解这两种语言的区别,请分别提出相关问题。 - user743382
@AlanStokes如果您对我在评论中明确解释的编辑有任何问题,而没有任何评论就将其还原,似乎相当无礼。我不想陷入回滚战争,但我认为,在原始状态下,这个问题过于宽泛,如果您阻碍了将其变得更好的尝试,那么可以,我会投票关闭。(当然,并不意味着它实际上会被关闭。) - user743382
@hvd 这样做合理吗?我想到两种语言,这种情况下都适用,它们非常相似。在你的提示之后,我删除了C++标志,但是答案出现并涵盖了C++的一部分,然后我恢复了C++标志,因为答案不适用。那我该怎么办呢? - DawidPi
@hvd问题显然涵盖了两个方面;将其更改为不这样做对我来说似乎不能保持精神。 (当时我没有看到您的评论,不确定为什么。) - Alan Stokes
1
@DawidPi 是的,如果你在一个问题中问了两个问题,并且实际上得到了一个回答来回答你的两个问题,那么把它留下来似乎是有道理的。实际上,对于C++来说,有一些相关的细节不是当前答案的一部分,我本来想把它们放在一起,但对于C来说没有任何意义... - user743382
3个回答

6

是的,这是符合标准的。

!DISABLED 是一个有效的 常量表达式,这就是 enum 值所需的全部内容。

enum State {DISABLED=0, ENABLED= (!DISABLED)};
//                               ^^^^^^^^^^^

当引用DISABLED时,编译器已经知道它的值,因此可以计算从中派生的表达式的值,即!DISABLED。 这是一种花哨的写法,相当于ENABLED=1


有没有任何有效的理由只写ENABLED = 1(即使= 1可能是多余的,除非你想要表达得更“清晰”)? - Jack
“以ENABLED=1的方式书写是不正确的”这种说法有些华而不实。由于枚举实际上是一个大小为“int”的类型,因此'!DISABLED'并不意味着加1,而是表示“非0”,这直接嵌入到编译器看到“ENABLED”时的代码中。 - user3629249
1
就C语言而言:“逻辑非运算符!的结果是0,如果其操作数的值与0不相等,则为1。结果具有int类型。表达式!E等同于(0==E)”(来自C11草案)。所以,在C中,这确实是一种花哨的写法,用于编写“ENABLED=1”。您似乎在谈论直接插入代码的宏,这与枚举完全不同。 - Ry-
对我来说,这表明C11草案重新定义了!value的含义,在这种情况下,比较将是:(0 == 0),这将是“true”,但不一定等于1。特别是因为“true”可以是任何值(在评估中,而不是在“true”的定义中),除了0。(这是比较永远不应该针对“true”的原因之一。我曾经使用过编译器,“true”被定义为-1(0xFFFFFFFF),另一个编译器则将“true”定义为2,所有这些都是内置的“true”定义,而不是像stdbool.h这样的头文件。 - user3629249
1
@user3629249:C11并未改变!value的含义。 - Keith Thompson
除非我弄错了,非零值在条件语句(if?:等)中被视为真值,但逻辑运算符始终会计算出0或1。这就是为什么标准的 int x = !!b 技巧能够奏效的原因。 - wchargin

3
根据C标准(6.2.1 标识符的作用域),每个枚举常量的作用域始于其定义枚举器出现在枚举器列表中之后。C++也一样(3.3.2 声明点)。对于枚举器,声明点是在其枚举定义之后立即发生。(例如:)
const int x = 12;
{ enum { x = x }; }

在这里,枚举器x被初始化为常量x的值,即12。 ——示例结束]

因此,在枚举中可以使用已定义的枚举器来定义下一个枚举器。

至于C类型_Bool,它出现在C 99中。在此标准之前,C中使用的是明示常量或枚举。

定义如下的枚举没有意义:

enum bool {false=0, true!=false};

因为类型_Bool已经有了两个值0和1。


3

是的,这个声明在C和C++中都是完全有效和可移植的。

在C和C++中,下面的代码:

enum State {DISABLED=0, ENABLED=!DISABLED};

这句话的意思是“完全等同于这个”。
enum State {DISABLED=0, ENABLED=1};

而且到了这个:
enum State {DISABLED, ENABLED};

但是因为微妙的不同,在C语言中,一元运算符!的结果是一个int类型的值,如果操作数不等于0,则值为0,否则为1。!x等同于x==0。(任何非零值在用作条件时都被视为true,但是!和==运算符等始终产生恰好为0或1的结果。)枚举常量始终是int类型;如果指定了值,则必要时将其转换为int。

(在1999年的标准中,C添加了类型_Bool,但是所有生成逻辑上“布尔”值的运算符仍然生成int类型的结果。)

在C++中,一元运算符!的结果是bool类型的。结果为false或true,而C的!运算符会分别产生0或1。与C类似,如果指定了值,则根据需要进行转换;bool值false和true分别转换为0和1。

在C中,枚举常量始终是int类型。在C ++中,它们属于枚举类型,在此示例中为enum State。

引用同一类型声明中较早的枚举常量是合法的。每个枚举常量在声明后变得可见。

至于像这样的内容:

enum bool { false = 0, true = !false );

比...更清晰
enum bool { false = 0, true = 1 };

(在C中;在C++中将是非法的),我不同意。对于熟悉C语言的人来说,常量1是完全清晰的。将其重写为!false并不会有帮助。事实上,当<stdbool.h>不可用时(这种情况现在很少见),我已经使用过:

typedef enum { false, true } bool;
< p >“false”和“true”将被赋予它们正确的值,这一事实显然易见。

< p >至于为什么C99没有使用像这样的“enum”定义,我认为这是因为每个枚举类型与某些实现定义的整数类型兼容。(对于gcc,通常是“unsigned int”或“int”)。委员会希望“_Bool”是一个不同的类型,并且其转换等级低于任何其他整数类型。(而且他们不能使“bool”成为关键字,否则会破坏现有代码。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接