12

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

像这样:

enum { constants.. }; typedef NSUInteger sometype;

使用 typedef 来获得 NSUInteger 的分配以在不强制转换的情况下工作的原因是什么?

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

有时仍会使用枚举标记名,例如_NSByteOrder 上。

这个答案也非常有用:What is a typedef enum in Objective-C? .

4

3 回答 3

12

几个原因:

原因一:灵活性:

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

声明一个枚举。您可以在任何地方使用这些值yesno并将maybe它们分配给任何整数类型。您也可以将其用作类型,通过编写

enum lickahoctor myVar = yes;

这很好,因为如果一个函数接受一个类型为 enum lickahoctor 的参数,你就会知道你可以分配yes,nomaybe给它。此外,调试器会知道,因此它将显示符号名称而不是数值。麻烦的是,编译器只会让您将您定义的值分配enum lickahoctormyVar. 例如,如果你想在基类中定义一些标志,然后在子类中添加更多标志,你不能​​这样做。

如果你使用 int 代替,你就没有这个问题。所以你想使用某种 int,所以你可以分配任意常量。

原因2:二进制兼容性:

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

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

原因 3:可读性和自文档

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

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

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

原因 4:支持位域

枚举类型的变量只支持从它们的选项中指定一个值。因此,如果您尝试实现位域,则不能将其键入为位域。此外,您需要使用无符号变量来避免符号扩展把您搞砸。

于 2010-02-12T20:42:14.743 回答
2

使用 typedef 来获得 NSUInteger 的分配以在不强制转换的情况下工作的原因是什么?

typedef 用于指定枚举值的基本类型。只要您截断该值,您始终可以将枚举值转换为另一种类型,方法是转换为较小的类型(NSUIntegerto unsigned short)。

NSIntegerNSUInteger通过为有符号和无符号整数提供与体系结构/平台无关的类型来简化应用程序的 64 位迁移。这样,无论 CPU 有多少位,应用程序都不需要重写。

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

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

  • NSInteger 提供 2^31 个正值和负值(在 32 位架构上)。
  • NSUInteger 提供 2^32 个正值(在 32 位架构上)。
  • 如果您的枚举仅包含正值,则使用 NSUInteger。
  • 如果您的枚举意味着同时包含正值和负值,则使用 NSInteger。
  • NSUInteger 通常用于标志枚举,因为它提供了 32 个不同的值(在 32 位架构上)可以随意组合。

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

于 2010-02-12T10:21:32.533 回答
1

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

  typedef enum { constants... } sometype;

无法保证数据类型的最终位大小。嗯,严格来说这不是真的,但它足够真实。最好以具体的数据大小定义 API,而不是根据所使用的编译器设置进行更改。

于 2010-02-11T22:30:20.543 回答