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

时间:2008-09-25 23:47:24

标签: c++ c enums c-preprocessor

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

例如,何时应该使用

enum {BUFFER = 1234}; 

#define BUFFER 1234   

18 个答案:

答案 0 :(得分:56)

enum定义了一个语法元素。

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

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

答案 1 :(得分:17)

在编译器看到代码之前,预处理器处理

#define语句,因此它基本上是一个文本替换(使用参数实际上更加智能化)。

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

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

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

答案 2 :(得分:8)

Define是一个预处理器命令,它就像在编辑器中执行“replace all”,它可以用另一个字符串替换字符串,然后编译结果。

枚举是一种特殊的类型,例如,如果你写:

enum ERROR_TYPES
{
   REGULAR_ERR =1,
   OK =0
}

存在一种名为ERROR_TYPES的新类型。 确实REGULAR_ERR产生为1但是从这种类型转换为int应该产生一个转换警告(如果你将编译器配置为高详细程度)。

要点: 它们都是相似的,但是当使用枚举时,您可以获得类型检查,并且通过使用定义,您只需替换代码字符串。

答案 3 :(得分:5)

在使用枚举的任何地方,枚举通常都优先于#define:

  • 调试器可以显示enum s值的符号名称(“openType: OpenExisting”,而不是“openType: 2
  • 您可以从名称冲突中获得更多保护,但这并不像以前那样糟糕(大多数编译器警告重新#define ition。

最大的区别是你可以使用枚举作为类型:

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

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

这为您提供了参数的类型检查(您不能轻易地混合使用openType和bufferSize),并且可以轻松找到哪些值有效,使您的界面更易于使用。有些IDE甚至可以给你 intellisense 代码完成!

答案 4 :(得分:4)

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

用于实施例如一堆模式,使用枚举使编译器可以捕获交换机中缺少的case - 语句。例如。

答案 5 :(得分:3)

#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卡住了......)。

答案 6 :(得分:3)

枚举可以将一个类别中的多个元素分组:

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

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

#define apple 1234
#define orange 12345

答案 7 :(得分:2)

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

答案 8 :(得分:2)

对于积分常数值,我更喜欢enum而不是#define。使用enum似乎没有任何缺点(折扣更多类型的微不足道的缺点),但你的优势是enum可以作用域,而#define标识符具有全局作用域那就是一切。

使用#define通常不是问题,但由于enum没有任何缺点,我会继续使用。

在C ++中,我通常也喜欢enumconst int,即使在C ++中,可以使用const int代替文字整数值(与C不同),因为{{1}可以移植到C(我仍然可以使用它)。

答案 9 :(得分:2)

除了已经写过的所有内容之外,有人说但没有显示,而是有趣的。 E.g。

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);

答案 10 :(得分:1)

枚举更多地用于枚举某种类型的集合,例如一周中的日期。如果你只需要一个常数,const int(或双倍等)肯定比枚举更好。我个人不喜欢#define(至少不是某些常量的定义),因为它不能给我类型安全,但如果它更适合你,你当然可以使用它。

答案 11 :(得分:1)

枚举相对于定义列表的另一个优点是,当在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,那就不是这种情况。

答案 12 :(得分:1)

除了上面列出的优点之外,您还可以将枚举的范围限制为类,结构或命名空间。就个人而言,我喜欢在任何时候在范围内使用最少数量的相关符号,这是使用枚举而不是#defines的另一个原因。

答案 13 :(得分:1)

如果你有一组常量(比如“星期几”),那么枚举会更好,因为它表明它们是分组的;而且,正如杰森所说,它们是类型安全的。如果它是一个全局常量(如版本号),则更多的是你使用#define;虽然这是很多争论的主题。

答案 14 :(得分:1)

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

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

答案 15 :(得分:1)

<强>枚举:

1。一般用于多个值

2. 在枚举中有一个是名称,另一个是名称的值必须区分但值可以相同。如果我们没有定义值那么枚举名称的第一个值是0秒值是1,依此类推,除非明确指定值。

3. 他们可能有类型,编译器可以打字检查它们

4. 使调试变得容易

5. 我们可以将其范围限制在一个级别。

<强>定义:

1。当我们只需定义一个值

2。它通常将一个字符串替换为另一个字符串。

3。范围是全球性的我们不能限制其范围

总的来说,我们必须使用枚举

答案 16 :(得分:0)

没有什么区别。 C标准表示枚举具有整数类型,枚举常量的类型为int,因此两者都可以与其他整数类型自由混合,没有错误。 (另一方面,如果在没有明确演员的情况下不允许这样的混合,明智地使用枚举可能会遇到某些编程错误。)

枚举的一些优点是自动分配数值,调试器可以在检查枚举变量时显示符号值,并且它们遵循块范围。 (当枚举被不加选择地混合时,编译器也可能生成非致命警告,因为这样做仍然可以被认为是坏风格,即使它不是严格违法的。)缺点是程序员几乎无法控制那些非致命警告;一些程序员也不喜欢无法控制枚举变量的大小。

答案 17 :(得分:0)

虽然上面的几个答案建议出于各种原因使用枚举,但我想指出使用定义在开发接口时具有实际优势。您可以引入新选项,并且可以让软件有条件地使用它们。

例如:


    #define OPT_X1 1 /* introduced in version 1 */
    #define OPT_X2 2 /* introduced in version  2 */

然后可以使用任一版本编译的软件


    #ifdef OPT_X2
    int flags = OPT_X2;
    #else
    int flags = 0;
    #endif

在枚举时,如果没有运行时特征检测机制,这是不可能的。