是否需要和/或首选将C枚举项目包裹在括号中,如果是的,则该实用程序是什么?
要使用哪个?
typedef enum
{
item_1 = 1,
item_2 = 5,
item_2 = 8,
item_2 = 10,
} formA_typeDef;
或者
typedef enum
{
item_1 = (1),
item_2 = (5),
item_2 = (8),
item_2 = (10),
} formB_typeDef;
我个人认为第一个,a_typedef;
是适当的格式,除非分配给该项目的值不是一个简单的整数,而是#define 例如:
#define REG1 0xFFF7U
#define REG2 0xFFFFU
typedef enum
{
item_1 = (REG1 | REG2 | 0x00U),
item_2 = (REG1 | REG2 | 0x01U),
item_2 = (REG1 | REG2 | 0x02U),
item_2 = (REG1 | REG2 | 0x03U),
} formC_typeDef;
Which one is to use?
typedef enum
{
item_1 = 1,
item_2 = 5,
item_2 = 8,
item_2 = 10,
} formA_typeDef;
or
typedef enum
{
item_1 = (1),
item_2 = (5),
item_2 = (8),
item_2 = (10),
} formB_typeDef;
I personally think that the first, A_typeDef;
is the adequate format to use, unless the value to assign to the item isn't a simple integer, but a combination of #define
such as:
#define REG1 0xFFF7U
#define REG2 0xFFFFU
typedef enum
{
item_1 = (REG1 | REG2 | 0x00U),
item_2 = (REG1 | REG2 | 0x01U),
item_2 = (REG1 | REG2 | 0x02U),
item_2 = (REG1 | REG2 | 0x03U),
} formC_typeDef;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
没有理由将
enum
常数周围使用冗余括号。第一个定义很好且可读。相反,如果要将常数定义为宏,则可以确保使用括号以避免在最终表达式中其扩展的宏扩展时避免优先错误。
使用枚举(无需括号):
使用宏(需要括号):
There is no reason to use redundant parentheses around the initializer expression for an
enum
constant. The first definition is fine and readable.Conversely, if you were to define the constants as macros, you would make sure so use parentheses to avoid precedence errors when the macro is replaced with its expansion in the final expressions.
Using enums (no parentheses needed):
Using macros (parentheses required):
。
。
前者,因为没有明智的论点可以使用后一个版本。
附带说明,使用
enum
存储位掩码是一个可怕的想法,因为枚举变量可以获得任何签名,并且保证可以签署枚举常数(item_1
)。而且您不希望位面具具有签名类型,因为这可能会导致其他地方的微妙错误。这就是为什么我们应该始终使用
u
/u
结束十六进制常数:#define reg1 0xfff7u
No.
No.
The former, because there exist no sensible arguments to use the latter version.
As a side note, using
enum
to store bit masks is a horrible idea since enumeration variables could get any signedness, and enumeration constants (item_1
) are guaranteed to be signed. And you don't want bit masks to have a signed type, as that could lead to subtle bugs elsewhere.And that would be the same reason as why we should always end hex constants with
u
/U
:#define REG1 0xFFF7u
将括号围绕一切的惯例非常适合对不好的书面宏的辩护。停止使用宏,您就不再必须如此防御。
在
#define reg2
的情况下,您实际上可能想将括号放在(reg2)
的使用周围括号已经被遗忘了 - 语言并不要求在宏中使用括号 - 并导致外表达式的解释方式有所不同。当然,将所有宏定义都括起来的房屋规则也有帮助。在您的情况下,唯一有用的操作是
?:
,因为所有其他操作的优先级都高于|
是否想象一下
#define reg2 cond2? 0x1200:0xff00
没有任何括号,
reg1 | reg2 | 0x02U
将被解释为:这实际上
是几乎总是应用0x1200的令人惊讶的效果,有效地忽略了cond2和最后一个参数。
为了确保您始终获得正确的行为,您想括起Reg2子句,实际上,既可能宏来获得完全安全的行为:
也就是说,在整个表达式上使用括号是完全多余的,至少在这种情况下,在我们“都知道”的地方,任务的优先级几乎是最低的。
通过在您的示例中选择
|
,它使得很难生成一个现实的示例。一个更现实的是,当用掩码和蒙版扩展时,扩展
但是按优先规则
,成为:对于令人惊讶的答案
0x003f
,因此,作为皮带和撑杆规则,每个“ value”宏定义应该具有周围的括号,并且您不信任/知道的宏的每个都应被括起来。以下内容永远不会被误解,但看起来确实很丑陋:
另外,当编译器认为您不知道优先规则时,请不要忽略编译器警告,但它们并不总是拯救您。
如果您绝对相信遵循第一个规则,或者您有一个可以看到定义的IDE,那么也许在使用宏值时,也许您不需要那么小心。当然,将来有人会出现并将一个定义更改为不安全的定义,但应在代码审查中发现这一点。您可以升级外部库标头。那你有多信任?
或者,停止使用宏,这可能意味着开始使用C ++ 11键入枚举。
The convention of putting brackets round everything is very much a defence against badly written macros. Stop using macros, and you stop having to be so defensive.
In the case of
#define REG2
you might actually want to place brackets round the usage of(REG2)
where REG2 is actually defined as an operation which unfortunately uses operations of lower precedence and the brackets have been forgotten - the language does not mandate the use of brackets in macros - and causes the outer expression to be interpreted differently. Of course a house rule that mandates all macro definitions are bracketed also helps.In your case the only useful operation would be
?:
, as all other operations are higher precedence than|
Imagine if
#define REG2 COND2 ? 0x1200 : 0xFF00
Without any brackets,
REG1 | REG2 | 0x02U
would be interpreted as:Which is actually
This would have the surprising effect of almost always applying 0x1200, effectively ignoring COND2 and the last argument.
To ensure you always get the correct behaviour, you would want to bracket the REG2 clause, indeed, do both possible macros to get completely safe behaviour:
That said, the use of brackets round the whole expression is completely redundant, at least in this case, where we "all know" that assignment has pretty much lowest priority.
By choosing
|
in your example it makes it quite difficult to generate a realistic example. A more realistic one is when ANDing with a mask:Is expanded as
But by precedence rules, becomes:
For the surprising answer
0x003F
So, as a belts-and-braces rule, every "value" macro you define should have surrounding brackets, and every usage of a macro you don't trust/know should be bracketed. The following will never be misinterpreted, but does look ugly:
Also, don't ignore the compiler warnings when the compiler thinks you don't know the precedence rules, but they won't always save you.
If you have absolute confidence that the first rule was followed, or you have an IDE that lets you see the definitions, then maybe you don't need to be so careful when using macro values. Of course, someone could come along in the future and change a definition into an unsafe one, but that should be spotted in code review. You might upgrade an external library header. So how trusting are you?
Alternatively, stop using macros, which probably means start using C++11 typed enums instead.