【问题标题】:Enums in C: What assumptions can be made about the value of the underlying variable?C 中的枚举:可以对基础变量的值做出哪些假设?
【发布时间】:2014-07-25 01:37:10
【问题描述】:

我正在编写一些通过 python 的 ctypes 模块调用 C dll 的 python 代码。

有问题的 DLL 在其头文件中将一些返回值定义为 enums:

//
// Device status
//
enum {
    FT_OK,
    FT_INVALID_HANDLE,
    FT_DEVICE_NOT_FOUND,
    FT_DEVICE_NOT_OPENED,
    FT_IO_ERROR,
    FT_INSUFFICIENT_RESOURCES,
    FT_INVALID_PARAMETER,
<continued---snip>
};

我是从 python 接口的,所以我没有原生枚举。我可以假设枚举的内容从0 的值开始,并为每个项目增加1吗?这很容易实现,但似乎我会依赖编译器的实现细节。

我已经对enum 变量的内部进行了一些挖掘,但我在内部找不到太多关于它们如何工作的信息。仅关于如何在 C/C#/whatever 中使用它们的文档。

我知道 enum 是否有各种变量的常量定义,我可以依赖它,但在这种情况下,我正在与我无权访问的外部代码交互(只是 dll) .

【问题讨论】:

  • 下面的答案直接解决了您的问题。但是,对枚举值做出任何假设的弱点在于,如果源确实决定为这些枚举中的任何一个分配一个值,那么您所有的硬编码假设都会被取消。理想情况下,您应该包装枚举,以便您可以通过某种方式实际访问这些值,从而确保您始终进行预期的比较。
  • @aruisdante - 是的,这就是困扰我的问题。实际上,如果枚举被重组,它也会破坏很多其他人的代码(至少需要重新编译任何链接到 DLL 的东西),所以假设它不会改变可能是安全的。
  • 一点也不。 enum 的全部意义在于,只要您使用枚举,而不依赖于枚举的值,就应该始终没问题。对于大多数面向用户的代码来说,枚举的实际值是什么无关紧要。通过将枚举正确地视为特殊值而不是 int 构建的任何东西都可以工作。因此,实现者可以决定分配一个值,以便他们可以例如通过返回枚举从应用程序的退出值中获取描述性错误代码。
  • 例如,如果我构建一个枚举来将索引表示为值数组,我可以任意更改这些索引处的值的位置,只要我更新枚举和所有代码建立在该枚举之上仍然可以正常工作。
  • @aruisdante - 我的观点是,如果 DLL 的枚举结构发生变化,任何与 DLL 接口的 c 代码都必须使用反映新枚举结构的头文件重新编译。您不需要更改用户代码,只需更改头文件,但您仍然需要重新编译,旧编译的代码无法链接新的dll。

标签: python c enums


【解决方案1】:

6.7.2.2 部分中的draft C99 standard 枚举说明符 段落3 说:

如果第一个枚举数没有=,则其枚举值 常数为 0。没有 = 的每个后续枚举数定义其 枚举常量作为得到的常量表达式的值 通过将前一个枚举常量的值加 1。 (这 使用枚举器 = 可能会产生枚举常量,其值与同一枚举中的其他值重复。)枚举的枚举数是 也称为其成员。

还提供了一个例子来说明:

enum hue { chartreuse, burgundy, claret=20, winedark };

然后说:

枚举值在集合 { 0, 1, 20, 21 } 中。

不清楚你是否关心底层类型,但第 4 段说:

每个枚举类型都应该兼容char,一个有符号整数 类型,或无符号整数类型。类型的选择是 实现定义,110),但应能够表示 枚举的所有成员的值。枚举类型是 直到终止枚举数列表的 } 之后才完成 声明。

【讨论】:

  • 宾果游戏。对标准的规范参考。优秀
  • 我可以依靠python中的duck-typing来忽略底层类型,所以至少在这个应用程序中,它并不重要。
【解决方案2】:

你是对的。

除非您专门为 enum 赋值,否则它遵循以下规则:

  • 第一个为零。
  • 后一个比前一个多一个。

例如:

enum {
    ZERO,
    ONE,
    SIX = 6,
    SEVEN,
    TWENTY = 20,
    TWENTYONE
} someNumbers;

完全按您的预期工作,enum 常量等于正确的值。

标准的控制部分(无论如何都是 C99)是6.7.2.2 Enumeration specifiers

带有 = 的枚举器将其枚举常量定义为常量表达式的值。如果第一个枚举数没有=,则其枚举常量的值为0。

后面的每个没有=的枚举数都将其枚举常量定义为前一个枚举常量的值加1得到的常量表达式的值。

【讨论】:

  • 那是 C 标准的一部分吗?我的搜索运气不佳。
  • @FakeName,我几乎可以肯定它是,虽然我不是语言律师。
  • @FakeName,查看更新。我在 C99 中引用了正确的部分,但它与 C11 中的规则相同。
【解决方案3】:

C 标准,第 6.7.2.2.1443 节:

如果第一个枚举数没有 =,则 其枚举常数的值为0。

和 6.7.2.2.1444:

后面的每个没有 = 的枚举数 将其枚举常量定义为值 通过添加获得的常数表达式 1 到上一个枚举的值 常数。

另外,6.7.2.2.1450 有一个例子:

示例以下片段:

enum hue { 黄绿色、酒红色、酒红色=20、酒红色 };

枚举色调颜色,*cp;

col = 酒红色;

cp = & col;

如果 (*cp != 酒红色)

/* ... */

使hue成为枚举的标签,并且 然后将 col 声明为具有该对象的对象 type 和 cp 作为指向具有 那种。枚举值在 设置 { 0, 1, 20, 21 }。

链接:The New C Standard: 6.7.2.2

【讨论】:

    【解决方案4】:

    您可以假设,枚举可以设置一个数字 FT_OK=100,然后之后的所有内容都将从那里递增。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-08
      • 1970-01-01
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多