枚举和定义语句之间的区别

时间:2020-03-06 14:45:27  来源:igfitidea点击:

在C / C ++中使用define语句和enum语句有什么区别(与C或者C ++一起使用时有什么区别)?

例如,什么时候应该使用

enum {BUFFER = 1234};

超过

#define BUFFER 1234

解决方案

"枚举"定义了一个语法元素。

#define是一个预处理程序指令,在编译器看到代码之前执行,因此不是C本身的语言元素。

通常,枚举是首选的,因为它们是类型安全的并且更容易发现。定义很难定位并且具有复杂的行为,例如,一段代码可以重新定义另一段代码的" #define"。这可能很难追踪。

Define是一个预处理程序命令,就像在编辑器中执行"全部替换"一样,它可以用另一个替换字符串,然后编译结果。

枚举是类型的一种特殊情况,例如,如果我们编写:

enum ERROR_TYPES
{
   REGULAR_ERR =1,
   OK =0
}

存在一个名为ERROR_TYPES的新类型。
确实REGULAR_ERR的结果为1,但是从此类型强制转换为int应该会产生强制转换警告(如果将编译器配置为高详细级别)。

概括:
它们都是相似的,但是使用枚举时,类型检查和定义都可以使我们简单地替换代码字符串。

如果我们有一组常量(例如"星期几"),则枚举会更可取,因为它表明它们已分组;而且,正如Jason所说,它们是类型安全的。如果它是一个全局常量(如版本号),那将是我们使用#define的更多内容;尽管这是很多辩论的主题。

#define语句是在编译器看到代码之前由预处理程序处理的,因此它基本上是文本替换(实际上,使用参数等会更智能)。

枚举是C语言本身的一部分,具有以下优点。

1 /它们可能具有类型,编译器可以对其进行类型检查。

2 /由于编译器可以使用它们,因此有关它们的符号信息可以传递给调试器,从而使调试更加容易。

通常在需要使用枚举的任何地方都比#define更喜欢枚举:

  • 调试器可以为我们显示一个枚举值的符号名称(" openType:OpenExisting`",而不是" openType:2"。
  • 我们可以获得更多的名称冲突保护,但这并不像以前那样糟糕(大多数编译器警告有关重新定义名称的问题。

最大的区别是我们可以将枚举用作类型:

// Yeah, dumb example
enum OpenType {
    OpenExisting,
    OpenOrCreate,
    Truncate
};

void OpenFile(const char* filename, OpenType openType, int bufferSize);

这使我们可以对参数进行类型检查(不能轻易混合使用openType和bufferSize),并且可以轻松地找到有效的值,从而使接口的使用更加容易。某些IDE甚至可以为我们提供智能的代码完成功能!

除了上面列出的优点之外,我们还可以将枚举的范围限制为类,结构或者名称空间。就个人而言,我希望每次都在作用域中使用最少数量的事件符号,这是使用枚举而非#defines的另一个原因。

与定义列表相比,枚举的另一个优点是,当未在switch语句中检查所有值时,编译器(至少为gcc)可以生成警告。例如:

enum {
    STATE_ONE,
    STATE_TWO,
    STATE_THREE
};

...

switch (state) {
case STATE_ONE:
    handle_state_one();
    break;
case STATE_TWO:
    handle_state_two();
    break;
};

在前面的代码中,编译器能够生成警告,指出不是所有枚举值都在开关中处理。如果状态是按#define进行的,则情况并非如此。

如果可能的话,最好使用枚举。使用枚举为编译器提供了有关源代码的更多信息,编译器从未看到过预处理器定义,因此携带的信息较少。

用于实施一堆模式,使用枚举可以使编译器例如在开关中捕获丢失的" case"语句。

枚举通常用于枚举某种类型的集合,例如一周中的几天。如果只需要一个常数,则const int(或者double等)肯定比枚举更好。我个人不喜欢#define(至少不喜欢某些常量的定义),因为它不能为我提供类型安全性,但是我们当然可以使用它,如果它更适合我们。

如果只想使用这个常量(比如说buffersize),那么我就不会使用枚举,而应该使用定义。我将枚举用于返回值(表示不同的错误条件)之类的东西,以及需要区分不同的"类型"或者"案例"的地方。在那种情况下,我们可以使用一个枚举创建一个可以在函数原型等中使用的新类型,然后编译器可以更好地检查该代码。

枚举可以将多个元素归为一类:

enum fruits{ apple=1234, orange=12345};

而#define只能创建不相关的常量:

#define apple 1234
#define orange 12345

#define是预处理程序命令,枚举使用C或者C ++语言。

在这种情况下,最好在#define上使用枚举。一件事是类型安全。另一个问题是,当我们拥有一个值序列时,只需在枚举中给出序列的开头,其他值将获得连续值。

enum {
  ONE = 1,
  TWO,
  THREE,
  FOUR
};

代替

#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4

附带说明一下,在某些情况下,我们可能必须使用#define(通常对于某些宏,如果我们需要能够构造包含常量的标识符),但这是一种宏黑魔术,而且非常罕见。如果我们要去这些肢体,则可能应该使用C ++模板(但是如果我们坚持使用C ...)。

除了已经写过的所有东西,一个人说了但没有显示,反而很有趣。例如。

enum action { DO_JUMP, DO_TURNL, DO_TURNR, DO_STOP };
//...
void do_action( enum action anAction, info_t x );

将动作视为类型可以使事情变得更清楚。使用define,我们可能已经写了

void do_action(int anAction, info_t x);

对于整数常量值,相对于#define,我更倾向于使用enum。使用enum似乎没有缺点(减少了更多键入的微小缺点),但是优点是enum可以范围化,而#define`标识符具有全局性,这使一切变得麻烦。

通常使用#define并不是问题,但是由于enum没有任何缺点,因此我同意了。

在C ++中,尽管在C ++中,const int可以代替文字整数值使用(与C语言不同),但我通常也更喜欢使用" enum"而不是" const int",因为enum可以移植到C语言中(我仍然可以工作很多)。

创建枚举不仅会创建文字,还会创建对这些文字进行分组的类型:这将使语义增加到编译器能够检查的代码中。

此外,在使用调试器时,我们可以访问枚举文字的值。 #define并非总是如此。