是否需要和/或首选将C枚举项目包裹在括号中,如果是的,则该实用程序是什么?

发布于 2025-01-27 19:01:28 字数 615 浏览 4 评论 0原文

要使用哪个?

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

墨落成白 2025-02-03 19:01:28

没有理由将enum常数周围使用冗余括号。第一个定义很好且可读。

相反,如果要将常数定义为宏,则可以确保使用括号以避免在最终表达式中其扩展的宏扩展时避免优先错误。

使用枚举(无需括号):

#define REG1 0x00F8U
#define REG2 0xFF00U

typedef enum {
    ITEM_1  = REG1 | REG2 | 0x00U,
    ITEM_2  = REG1 | REG2 | 0x01U,
    ITEM_3  = REG1 | REG2 | 0x02U,
    ITEM_4  = REG1 | REG2 | 0x03U,
} formC_typeDef;

使用宏(需要括号):

#define ITEM_1  (REG1 | REG2 | 0x00U)
#define ITEM_2  (REG1 | REG2 | 0x01U)
#define ITEM_3  (REG1 | REG2 | 0x02U)
#define ITEM_4  (REG1 | REG2 | 0x03U)

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):

#define REG1 0x00F8U
#define REG2 0xFF00U

typedef enum {
    ITEM_1  = REG1 | REG2 | 0x00U,
    ITEM_2  = REG1 | REG2 | 0x01U,
    ITEM_3  = REG1 | REG2 | 0x02U,
    ITEM_4  = REG1 | REG2 | 0x03U,
} formC_typeDef;

Using macros (parentheses required):

#define ITEM_1  (REG1 | REG2 | 0x00U)
#define ITEM_2  (REG1 | REG2 | 0x01U)
#define ITEM_3  (REG1 | REG2 | 0x02U)
#define ITEM_4  (REG1 | REG2 | 0x03U)
始于初秋 2025-02-03 19:01:28

是否需要

它是首选

要使用哪一个?

前者,因为没有明智的论点可以使用后一个版本。


附带说明,使用enum存储位掩码是一个可怕的想法,因为枚举变量可以获得任何签名,并且保证可以签署枚举常数(item_1)。而且您不希望位面具具有签名类型,因为这可能会导致其他地方的微妙错误。

这就是为什么我们应该始终使用u/u结束十六进制常数:#define reg1 0xfff7u

Is it required

No.

Is it preferred

No.

Which one is to use?

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

清风挽心 2025-02-03 19:01:28

将括号围绕一切的惯例非常适合对不好的书面宏的辩护。停止使用宏,您就不再必须如此防御。

#define reg2的情况下,您实际上可能想将括号放在(reg2)的使用周围括号已经被遗忘了 - 语言并不要求在宏中使用括号 - 并导致外表达式的解释方式有所不同。当然,将所有宏定义都括起来的房屋规则也有帮助。

在您的情况下,唯一有用的操作是?:,因为所有其他操作的优先级都高于|

是否想象一下#define reg2 cond2? 0x1200:0xff00

没有任何括号,reg1 | reg2 | 0x02U将被解释为:

REG1 | COND2 ? 0x1200U : 0xFF00U | 0x02U

这实际上

(REG1 | COND2) ? 0x1200U : (0xFF00U | 0x02U)

是几乎总是应用0x1200的令人惊讶的效果,有效地忽略了cond2和最后一个参数。

为了确保您始终获得正确的行为,您想括起Reg2子句,实际上,既可能宏来获得完全安全的行为:

(REG1) | (REG2) | 0x02U

也就是说,在整个表达式上使用括号是完全多余的,至少在这种情况下,在我们“都知道”的地方,任务的优先级几乎是最低的。

通过在您的示例中选择|,它使得很难生成一个现实的示例。一个更现实的是,当用掩码和蒙版扩展时,

#define MASK1 0x00F0U|0x000F

unsigned v = 0x1234U & MASK1;

扩展

unsigned v = 0x1234U & 0x00F0U|0x000F;

但是按优先规则

unsigned v = (0x1234 & 0x00F0U) | 0x000F;

,成为:对于令人惊讶的答案0x003f

因此,作为皮带和撑杆规则,每个“ value”宏定义应该具有周围的括号,并且您不信任/知道的宏的每个都应被括起来。以下内容永远不会被误解,但看起来确实很丑陋:

#define MASK1 (0x00F0U|0x000F)

unsigned v = 0x1234U & (MASK1);

另外,当编译器认为您不知道优先规则时,请不要忽略编译器警告,但它们并不总是拯救您。

如果您绝对相信遵循第一个规则,或者您有一个可以看到定义的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:

REG1 | COND2 ? 0x1200U : 0xFF00U | 0x02U

Which is actually

(REG1 | COND2) ? 0x1200U : (0xFF00U | 0x02U)

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:

(REG1) | (REG2) | 0x02U

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:

#define MASK1 0x00F0U|0x000F

unsigned v = 0x1234U & MASK1;

Is expanded as

unsigned v = 0x1234U & 0x00F0U|0x000F;

But by precedence rules, becomes:

unsigned v = (0x1234 & 0x00F0U) | 0x000F;

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:

#define MASK1 (0x00F0U|0x000F)

unsigned v = 0x1234U & (MASK1);

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文