“默认”枚举价值,全球变量或枚举的一部分
好吧,我和我在一起。我有一个互斥的应用程序。为了方便起见,我还提供了作为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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论