“默认”枚举价值,全球变量或枚举的一部分

发布于 2025-02-02 01:11:16 字数 1973 浏览 0 评论 0原文

好吧,我和我在一起。我有一个互斥的应用程序。为了方便起见,我还提供了作为enum一部分的“默认”,该以前是用宏观定时确定的。

typedef enum {
  FRUIT_APPLE,
  FRUIT_ORANGE,
  FRUIT_PEAR
} Fruit;

#if defined(HAVE_APPLES)
#  define FRUIT_DEFAULT FRUIT_APPLE
#elif defined(HAVE_ORANGES)
#  define FRUIT_DEFAULT FRUIT_ORANGE
#else
#  define FRUIT_DEFAULT FRUIT_PEAR
#endif

void foo(Fruit f)
{
  switch(f) {
    case FRUIT_APPLE:
      // etc...
  }
}

现在,我添加了一个功能,用户可以通过某些setDefaultFruit()函数更改运行时的默认设备,但是我对实现此目的的最佳长期方法有些撕裂。


直接将其添加到枚举中,

我还需要一个内部辅助函数转换值。

// Fruit_private.c
Fruit private_default;

Fruit convert_default(Fruit f) 
{
  if (f == FRUIT_DEFAULT) f = private_default;
  return f;
}

需要这样的使用:

typedef enum {
  FRUIT_APPLE,
  FRUIT_ORANGE,
  FRUIT_PEAR,
  FRUIT_DEFAULT
} Fruit;

void foo(Fruit f)
{
  switch(convert_default(f)) {
    case FRUIT_APPLE:
      // etc...
  }
}

PROS:

  • 该值仍由编译器静态确定。
  • 该值是恒定的,用户无法更改它(如果不浏览正确的访问功能)。
  • 用户通过传递未结合的值来摸索呼叫的机会更少(我可以简单地检查fruit_apple< f< = fruit_default)。

缺点:

  • 开发人员必须记住调用额外的转换步骤。
  • 用户无法检查“默认值”是否等于没有额外功能的某些特定水果

它只是将其添加到枚举

typedef enum {
  FRUIT_APPLE,
  FRUIT_ORANGE,
  FRUIT_PEAR
} Fruit;

extern Fruit FRUIT_DEFAULT;

void foo(Fruit f)
{
  switch(f) {
    case FRUIT_APPLE:
      // etc...
  }
}

,而只是将其作为全局变量专业人士而生:

  • 开发人员不能忘记转换值。
  • 用户可以检查默认值是什么,即frue_default == fruit_apple完全按预期工作。

缺点:

  • 由于它是非const全局它。
  • 全球变量通常是不可能的,并且可能会抑制其他优化(它们可以随时保持任何值,任何指针都可以别名它们) [1]

[1] :在您了解过早优化之前,我知道。通过在“利弊”部分中包括这一点,我并不是暗示这是世界上最大的交易,只是要记住这一点。

Alrighty bear with me. I have an application where I have some mutually exclusive enumeration. For convenience I also provided a "default" that acted as part of the enum, which was previously statically determined at configure-time with a macro.

typedef enum {
  FRUIT_APPLE,
  FRUIT_ORANGE,
  FRUIT_PEAR
} Fruit;

#if defined(HAVE_APPLES)
#  define FRUIT_DEFAULT FRUIT_APPLE
#elif defined(HAVE_ORANGES)
#  define FRUIT_DEFAULT FRUIT_ORANGE
#else
#  define FRUIT_DEFAULT FRUIT_PEAR
#endif

void foo(Fruit f)
{
  switch(f) {
    case FRUIT_APPLE:
      // etc...
  }
}

I am now adding a feature whereby the user can change the default at runtime via some SetDefaultFruit() function, but I am a bit torn on the best long-term way of implementing this.


Add it to the enum directly

I would also need an internal helper function convert the value.

// Fruit_private.c
Fruit private_default;

Fruit convert_default(Fruit f) 
{
  if (f == FRUIT_DEFAULT) f = private_default;
  return f;
}

Which would need to be used like so:

typedef enum {
  FRUIT_APPLE,
  FRUIT_ORANGE,
  FRUIT_PEAR,
  FRUIT_DEFAULT
} Fruit;

void foo(Fruit f)
{
  switch(convert_default(f)) {
    case FRUIT_APPLE:
      // etc...
  }
}

Pros:

  • The value is still statically determined by compiler.
  • The value is constant, and user cannot change it (without going through the proper access function).
  • Less chance the user fumbles the call by passing an out-of-bounds value (I can simply check FRUIT_APPLE < f <= FRUIT_DEFAULT).

Cons:

  • Devs must remember to call extra conversion step.
  • Users cannot check if the "default" is equal to some specific Fruit without an extra function.

Global Variable

Instead of adding to enum, it simply lives as a global variable

typedef enum {
  FRUIT_APPLE,
  FRUIT_ORANGE,
  FRUIT_PEAR
} Fruit;

extern Fruit FRUIT_DEFAULT;

void foo(Fruit f)
{
  switch(f) {
    case FRUIT_APPLE:
      // etc...
  }
}

Pros:

  • Devs cannot forget to convert the value.
  • Trivial for users to check what the default is, i.e. FRUIT_DEFAULT == FRUIT_APPLE works exactly as expected.

Cons:

  • Since it is a non-const global, the value could be changed from anywhere at any time (including by the user) without the library knowing about it, so it may be difficult to error-check it.
  • global variables are generally speaking un-optimizable and may inhibit other optimizations (they could hold any value at any time, and any pointer could alias them)[1].

[1]: Before you get your pitchforks out about premature optimization, yes I understand. By including this point in the cons section I am not implying this is the biggest deal in the world, just that it is something to keep in mind.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文