是什么让C,宏或枚举更好?

时间:2013-06-15 16:05:25

标签: c macros enums

我对何时使用宏或枚举感到困惑。两者都可以用作常量,但它们之间有什么区别,哪一个有什么优势?它是否与编译器级别有关?

6 个答案:

答案 0 :(得分:31)

就可读性而言,枚举比宏更好,因为相关值被组合在一起。此外,enum定义了一个新类型,因此程序的读者可以更容易地确定可以传递给相应参数的内容。

比较

#define UNKNOWN  0
#define SUNDAY   1
#define MONDAY   2
#define TUESDAY  3
...
#define SATURDAY 7

typedef enum {
    UNKNOWN
,   SUNDAY
,   MONDAY
,   TUESDAY
,   ...
,   SATURDAY
} Weekday;

阅读这样的代码要容易得多

void calendar_set_weekday(Weekday wd);

比这个

void calendar_set_weekday(int wd);

因为你知道哪些常数可以通过。

答案 1 :(得分:18)

宏是一个预处理程序,编译后的代码不知道您创建的标识符。在代码到达编译器之前,它们已经被预处理器替换。枚举是一个编译时实体,编译后的代码保留有关该符号的完整信息,该信息在调试器(和其他工具)中可用。

首选枚举(如果可以的话)。

答案 2 :(得分:10)

在C中,最好使用枚举来实际枚举:当某个变量可以包含多个可以给出名称的值中的一个时。枚举的一个优点是编译器可以执行超出语言要求的某些检查,例如枚举类型上的switch语句不会丢失其中一种情况。枚举标识符也传播到调试信息中。在调试器中,您可以将标识符名称视为枚举变量的值,而不仅仅是数值。

枚举只能用于创建整数类型的符号常量的副作用。例如:

enum { buffer_size = 4096 };  /* we don't care about the type */

这种做法并没有那么广泛。首先,buffer_size将用作整数而不是枚举类型。调试器不会将4096呈现为buffer_size,因为该值不会被表示为枚举类型。如果您声明了一些char array[max_buffer_size];,则sizeof array将不会显示为buffer_size。在这种情况下,枚举常量在编译时消失,因此它也可能是一个宏。并且存在缺点,例如无法控制其确切类型。 (在某些情况下,翻译的预处理阶段的输出被捕获为文本可能会有一些小优势。宏将变为4096,而buffer_size将保持为buffer_size。 / p>

预处理器符号允许我们这样做:

#define buffer_size 0L /* buffer_size is a long int */

请注意,C <limits.h>UINT_MAX的各种值(如#if ULONG_MAX > UINT_MAX /* unsigned long is wider than unsigned int */ #endif )是预处理符号,而不是枚举符号,原因很充分,因为这些标识符需要具有精确确定的类型。预处理器符号的另一个优点是我们可以测试它的存在,甚至根据它的值做出决定:

enum modem_control { mc_dsr = 0x1, mc_dtr = 0x2, mc_rts = 0x4, ... }

当然我们也可以测试枚举常量,但不能以我们可以根据结果更改全局声明的方式。

枚举也不适用于位掩码:

{{1}}

它只是没有意义,因为当值与按位OR组合时,它们会产生一个超出类型的值。这样的代码也会引起头疼,如果它被移植到C ++,它有(更多)类型安全的枚举。

答案 3 :(得分:9)

请注意,宏和枚举之间存在一些差异,这些属性中的任何一个都可能使它们(un)适合作为特定常量。

  • 枚举符号(与int兼容)。在任何需要无符号类型的上下文中(特别考虑按位操作!),枚举已经结束。
  • 如果long long比int宽,则大常量将不适合枚举。
  • 枚举的大小为sizeof(int)。对于较小值的数组(最多可以说是CHAR_MAX),您可能需要char foo[]而不是enum foo[]数组。
  • 枚举是整数。你不能拥有enum funny_number { PI=3.14, E=2.71 }
  • 枚举是C89功能; K&amp; R编译器(公认的古老)不理解它们。

答案 4 :(得分:4)

如果宏被正确实现(即它在替换时不会遇到关联性问题),那么在两者适用的情况下,即在情境中宏和枚举常量之间的适用性没有太大差异你需要专门签名的整数常量。

但是,在一般情况下,宏提供了更灵活的功能。枚举将特定类型强加到常量上:它们将具有类型int(或者可能是更大的有符号整数类型),并且它们将始终被签名。使用宏,您可以使用常量语法,后缀和/或显式类型转换来生成任何类型的常量。

当您有一组紧密关联的连续整数常量时,枚举最有效。当你根本不关心常量的实际值时,即当你只关心它们某些表现良好的唯一值时,它们的效果特别好。在所有其他情况下,宏是更好的选择(或基本上是唯一的选择)。

答案 5 :(得分:2)

实际上,差别不大。它们同样可用作程序中的常量。有些人可能因为文体方面的原因而更喜欢其中一种,但我想不出任何技术上的理由来偏爱另一种。

一个区别是宏允许您控制相关常量的整数类型。但是enum将使用int

#define X 100L
enum { Y = 100L };

printf("%ld\n", X);
printf("%d\n", Y); /* Y has int type */