为什么cocoa到处都没有使用相同的枚举声明样式?

时间:2022-04-10 16:44:38

I was wondering what is the rationale behind different styles of enum declaration on cocoa?

我想知道可可的不同风格的枚举声明背后的理由是什么?

Like this:

喜欢这个:

enum { constants.. }; typedef NSUInteger sometype;

Is the reason to use typedef to get assigments to NSUInteger to work without casting?

是否有理由使用typedef来获取NSUInteger的分配而不进行强制转换?

Sometimes the typedef is either of NSInteger/NSUInteger, why not use NSInteger always? Is there real benefit using NSUInteger?

有时typedef是NSInteger / NSUInteger,为什么不总是使用NSInteger?使用NSUInteger真的有好处吗?

Enum tagnames are still used sometimes, like here on _NSByteOrder.

Enum标记名有时仍在使用,例如_NSByteOrder。

This answer was very useful too: What is a typedef enum in Objective-C?.

这个答案也非常有用:Objective-C中的typedef枚举是什么?

3 个解决方案

#1


12  

Several reasons:

几个原因:

Reason 1: Flexibility:

原因1:灵活性:

enum lickahoctor { yes = 0, no = 1, maybe = 2 };

declares an enumeration. You can use the values yes, no and maybe anywhere and assign them to any integral type. You can also use this as a type, by writing

声明一个枚举。您可以使用yes,no和no值,并将它们分配给任何整数类型。您也可以通过写作将其用作类型

enum lickahoctor myVar = yes;

This makes it nice because if a function takes a parameter with the type enum lickahoctor you'll know that you can assign yes, no or maybe to it. Also, the debugger will know, so it'll display the symbolic name instead of the numerical value. Trouble is, the compiler will only let you assign values you've defined in enum lickahoctor to myVar. If you for example want to define a few flags in the base class, then add a few more flags in the subclass, you can't do it this way.

这很好,因为如果一个函数采用enum lickahoctor类型的参数,你就会知道你可以分配yes,no或者它。此外,调试器将知道,因此它将显示符号名称而不是数值。麻烦的是,编译器只允许你将你在enum lickahoctor中定义的值分配给myVar。例如,如果您想在基类中定义一些标志,那么在子类中添加一些标志,就不能这样做。

If you use an int instead, you don't have that problem. So you want to use some sort of int, so you can assign arbitrary constants.

如果您使用int,则不会出现此问题。所以你想使用某种int,所以你可以分配任意常量。

Reason 2: Binary compatibility:

原因2:二进制兼容性:

The compiler chooses a nice size that fits all the constants you've defined in an enum. There's no guarantee what you will get. So if you write a struct containing such a variable directly to a file, there is no guarantee that it will still be the same size when you read it back in with the next version of your app (according to the C standard, at least -- it's not quite that bleak in practice).

编译器选择一个适合你在枚举中定义的所有常量的大小。不能保证你会得到什么。因此,如果您将包含此类变量的结构直接写入文件,则无法保证当您使用下一版本的应用程序将其读回时,它仍将保持相同的大小(根据C标准,至少 - - 在实践中并不是那么黯淡。

If you use some kind of int instead, the platform usually guarantees a particular size for that number. Especially if you use one of the types guaranteed to be a particular size, like int32_t/uint32_t.

如果您使用某种int,平台通常会保证该数字的特定大小。特别是如果你使用其中一种保证是特定大小的类型,比如int32_t / uint32_t。

Reason 3: Readability and self-documentation

原因3:可读性和自我记录

When you declare myVar above, it's immediately obvious what values you can put in it. If you just use an int, or an uint32_t, it isn't. So what you do is you use

当你在上面声明myVar时,你可以立即明白你可以放入什么值。如果您只使用int或uint32_t,则不是。所以你做的就是用

enum { yes, no, maybe };
typedef uint32_t lickahoctor;

to define a nice name for the integer somewhere near the constants that will remind people that a variable of this type can hold this value. But you still get the benefit of a predictable, fixed size and the ability to define additional values in subclasses, if needed.

为常量附近的整数定义一个很好的名称,它会提醒人们这种类型的变量可以保存这个值。但是,如果需要,您仍然可以获得可预测的固定大小以及在子类中定义其他值的能力。

Reason 4: Support for bitfields

原因4:支持位域

enum-typed variables only support assigning exactly one value from their options. So if you're trying to implement a bit field, you can't type it as a bitfield. Furthermore, you need to use unsigned variables to avoid sign extension from screwing you over.

枚举变量仅支持从其选项中精确分配一个值。因此,如果您尝试实现位字段,则无法将其键入为位域。此外,您需要使用无符号变量来避免符号扩展使您失败。

#2


2  

Is the reason to use typedef to get assigments to NSUInteger to work without casting?

是否有理由使用typedef来获取NSUInteger的分配而不进行强制转换?

The typedef is used to specify the base type for the enumeration values. You can always cast a enumeration value to another type as long as you truncate the value, by casting to a smaller type (NSUInteger to unsigned short).

typedef用于指定枚举值的基本类型。只要截断值,通过强制转换为较小的类型(NSUInteger为unsigned short),您始终可以将枚举值强制转换为其他类型。

NSInteger and NSUInteger were introduced to ease the 64 bits migration of applications, by providing a architecture/platform independent type for both signed and unsigned integers. This way, no matter how many bits the CPU has, applications do no need to be rewritten.

通过为有符号和无符号整数提供架构/平台无关类型,引入了NSInteger和NSUInteger以简化应用程序的64位迁移。这样,无论CPU有多少位,都不需要重写应用程序。

Sometimes the typedef is either of NSInteger/NSUInteger, why not use NSInteger always? Is there real benefit using NSUInteger?

有时typedef是NSInteger / NSUInteger,为什么不总是使用NSInteger?使用NSUInteger真的有好处吗?

The choice depends on the values in the enumeration. Some enumerations have a lot of values, so they need all the bits available:

选择取决于枚举中的值。有些枚举有很多值,所以它们需要所有可用的位:

  • NSInteger offers 2^31 positive and negative values (on 32 bits architecture).
  • NSInteger提供2 ^ 31个正值和负值(32位架构)。
  • NSUInteger offers 2^32 positive values (on 32 bits architecture).
  • NSUInteger提供2 ^ 32个正值(32位架构)。
  • If you enumeration is meant to only contain positive values, then use NSUInteger.
  • 如果枚举仅包含正值,则使用NSUInteger。
  • If you enumeration is meant to contain both positive and negative values, then use NSInteger.
  • 如果枚举意味着包含正值和负值,则使用NSInteger。
  • NSUInteger is usually used for flag enumeration, as it provides 32 distinct values (on 32 bits architecture) to be combined at will.
  • NSUInteger通常用于标志枚举,因为它提供32个不同的值(在32位体系结构上),可以随意组合。

I don't know if there a rule of choice in Apple development's team for that. I hope so...

我不知道Apple开发团队是否有选择规则。但愿如此...

#3


1  

Whilst you could use something like

虽然你可以使用类似的东西

  typedef enum { constants... } sometype;

there is no guarantee about the eventual bitsize of the datatype. Well, thats not strictly true, but its true enough. Its better for APIs to be defined in concrete data sizes, than with something that can change depending on the compiler settings being used.

无法保证数据类型的最终比特化。嗯,这不是严格意义上的,但它足够真实。它更适合在具体数据大小中定义API,而不是根据所使用的编译器设置可以更改的内容。

#1


12  

Several reasons:

几个原因:

Reason 1: Flexibility:

原因1:灵活性:

enum lickahoctor { yes = 0, no = 1, maybe = 2 };

declares an enumeration. You can use the values yes, no and maybe anywhere and assign them to any integral type. You can also use this as a type, by writing

声明一个枚举。您可以使用yes,no和no值,并将它们分配给任何整数类型。您也可以通过写作将其用作类型

enum lickahoctor myVar = yes;

This makes it nice because if a function takes a parameter with the type enum lickahoctor you'll know that you can assign yes, no or maybe to it. Also, the debugger will know, so it'll display the symbolic name instead of the numerical value. Trouble is, the compiler will only let you assign values you've defined in enum lickahoctor to myVar. If you for example want to define a few flags in the base class, then add a few more flags in the subclass, you can't do it this way.

这很好,因为如果一个函数采用enum lickahoctor类型的参数,你就会知道你可以分配yes,no或者它。此外,调试器将知道,因此它将显示符号名称而不是数值。麻烦的是,编译器只允许你将你在enum lickahoctor中定义的值分配给myVar。例如,如果您想在基类中定义一些标志,那么在子类中添加一些标志,就不能这样做。

If you use an int instead, you don't have that problem. So you want to use some sort of int, so you can assign arbitrary constants.

如果您使用int,则不会出现此问题。所以你想使用某种int,所以你可以分配任意常量。

Reason 2: Binary compatibility:

原因2:二进制兼容性:

The compiler chooses a nice size that fits all the constants you've defined in an enum. There's no guarantee what you will get. So if you write a struct containing such a variable directly to a file, there is no guarantee that it will still be the same size when you read it back in with the next version of your app (according to the C standard, at least -- it's not quite that bleak in practice).

编译器选择一个适合你在枚举中定义的所有常量的大小。不能保证你会得到什么。因此,如果您将包含此类变量的结构直接写入文件,则无法保证当您使用下一版本的应用程序将其读回时,它仍将保持相同的大小(根据C标准,至少 - - 在实践中并不是那么黯淡。

If you use some kind of int instead, the platform usually guarantees a particular size for that number. Especially if you use one of the types guaranteed to be a particular size, like int32_t/uint32_t.

如果您使用某种int,平台通常会保证该数字的特定大小。特别是如果你使用其中一种保证是特定大小的类型,比如int32_t / uint32_t。

Reason 3: Readability and self-documentation

原因3:可读性和自我记录

When you declare myVar above, it's immediately obvious what values you can put in it. If you just use an int, or an uint32_t, it isn't. So what you do is you use

当你在上面声明myVar时,你可以立即明白你可以放入什么值。如果您只使用int或uint32_t,则不是。所以你做的就是用

enum { yes, no, maybe };
typedef uint32_t lickahoctor;

to define a nice name for the integer somewhere near the constants that will remind people that a variable of this type can hold this value. But you still get the benefit of a predictable, fixed size and the ability to define additional values in subclasses, if needed.

为常量附近的整数定义一个很好的名称,它会提醒人们这种类型的变量可以保存这个值。但是,如果需要,您仍然可以获得可预测的固定大小以及在子类中定义其他值的能力。

Reason 4: Support for bitfields

原因4:支持位域

enum-typed variables only support assigning exactly one value from their options. So if you're trying to implement a bit field, you can't type it as a bitfield. Furthermore, you need to use unsigned variables to avoid sign extension from screwing you over.

枚举变量仅支持从其选项中精确分配一个值。因此,如果您尝试实现位字段,则无法将其键入为位域。此外,您需要使用无符号变量来避免符号扩展使您失败。

#2


2  

Is the reason to use typedef to get assigments to NSUInteger to work without casting?

是否有理由使用typedef来获取NSUInteger的分配而不进行强制转换?

The typedef is used to specify the base type for the enumeration values. You can always cast a enumeration value to another type as long as you truncate the value, by casting to a smaller type (NSUInteger to unsigned short).

typedef用于指定枚举值的基本类型。只要截断值,通过强制转换为较小的类型(NSUInteger为unsigned short),您始终可以将枚举值强制转换为其他类型。

NSInteger and NSUInteger were introduced to ease the 64 bits migration of applications, by providing a architecture/platform independent type for both signed and unsigned integers. This way, no matter how many bits the CPU has, applications do no need to be rewritten.

通过为有符号和无符号整数提供架构/平台无关类型,引入了NSInteger和NSUInteger以简化应用程序的64位迁移。这样,无论CPU有多少位,都不需要重写应用程序。

Sometimes the typedef is either of NSInteger/NSUInteger, why not use NSInteger always? Is there real benefit using NSUInteger?

有时typedef是NSInteger / NSUInteger,为什么不总是使用NSInteger?使用NSUInteger真的有好处吗?

The choice depends on the values in the enumeration. Some enumerations have a lot of values, so they need all the bits available:

选择取决于枚举中的值。有些枚举有很多值,所以它们需要所有可用的位:

  • NSInteger offers 2^31 positive and negative values (on 32 bits architecture).
  • NSInteger提供2 ^ 31个正值和负值(32位架构)。
  • NSUInteger offers 2^32 positive values (on 32 bits architecture).
  • NSUInteger提供2 ^ 32个正值(32位架构)。
  • If you enumeration is meant to only contain positive values, then use NSUInteger.
  • 如果枚举仅包含正值,则使用NSUInteger。
  • If you enumeration is meant to contain both positive and negative values, then use NSInteger.
  • 如果枚举意味着包含正值和负值,则使用NSInteger。
  • NSUInteger is usually used for flag enumeration, as it provides 32 distinct values (on 32 bits architecture) to be combined at will.
  • NSUInteger通常用于标志枚举,因为它提供32个不同的值(在32位体系结构上),可以随意组合。

I don't know if there a rule of choice in Apple development's team for that. I hope so...

我不知道Apple开发团队是否有选择规则。但愿如此...

#3


1  

Whilst you could use something like

虽然你可以使用类似的东西

  typedef enum { constants... } sometype;

there is no guarantee about the eventual bitsize of the datatype. Well, thats not strictly true, but its true enough. Its better for APIs to be defined in concrete data sizes, than with something that can change depending on the compiler settings being used.

无法保证数据类型的最终比特化。嗯,这不是严格意义上的,但它足够真实。它更适合在具体数据大小中定义API,而不是根据所使用的编译器设置可以更改的内容。