42

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

4

7 回答 7

41

在可读性方面,枚举比宏更好的常量,因为相关的值被组合在一起。此外,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);

因为您知道可以传递哪些常量。

于 2013-06-15T16:10:14.547 回答
21

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

更喜欢枚举(如果可以的话)。

于 2013-06-15T16:09:04.413 回答
14

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

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

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

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

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

#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, ... }

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

于 2013-06-15T18:38:39.070 回答
10

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

  • 枚举已签名(与 int 兼容)。在任何需要无符号类型的上下文中(尤其是按位运算!),枚举都不存在。
  • 如果 long long 比 int 宽,则大常量将不适合枚举。
  • 枚举的大小是(通常)sizeof(int)。对于小值的数组(最多说,CHAR_MAX),您可能需要 achar foo[]而不是enum foo[]数组。
  • 枚举是整数。你不能有enum funny_number { PI=3.14, E=2.71 }
  • 枚举是 C89 的一个特性;K&R 编译器(诚然是古老的)不理解它们。
于 2013-06-15T17:50:11.450 回答
4

如果正确实现了宏(即在被替换时不会出现关联性问题),那么在两者都适用的情况下,即在您需要有符号整数常量的情况下,宏和枚举常量之间的适用性没有太大差异。

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

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

于 2013-06-15T18:12:35.960 回答
3

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

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

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

printf("%ld\n", X);
printf("%d\n", Y); /* Y has int type */
于 2013-06-15T16:31:53.703 回答
-1

enum有一个优点:块范围:

{ enum { E = 12 }; }
{ enum { E = 13 }; }

使用宏需要#undef.

于 2022-02-04T17:05:25.463 回答