C语言 什么使 C、宏或枚举中的常量更好?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17125505/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:42:21  来源:igfitidea点击:

What makes a better constant in C, a macro or an enum?

cmacrosenums

提问by Varun Chhangani

I am confused about when to use macros or enums. Both can be used as constants, but what is the difference between them and what is the advantage of either one? Is it somehow related to compiler level or not?

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

回答by dasblinkenlight

In terms of readability, enumerations make better constants than macros, because related values are grouped together. In addition, enumdefines a new type, so the readers of your program would have easier time figuring out what can be passed to the corresponding parameter.

在可读性方面,枚举是比宏更好的常量,因为相关的值被组合在一起。此外,还enum定义了一个新类型,因此程序的读者可以更轻松地找出可以传递给相应参数的内容。

Compare

相比

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

to

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

It is much easier to read code like this

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

void calendar_set_weekday(Weekday wd);

than this

比这个

void calendar_set_weekday(int wd);

because you know which constants it is OK to pass.

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

回答by Ziffusion

A macro is a preprocessor thing, and the compiled code has no idea about the identifiers you create. They have been already replaced by the preprocessor before the code hits the compiler. An enum is a compile time entity, and the compiled code retains full information about the symbol, which is available in the debugger (and other tools).

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

Prefer enums (when you can).

首选枚举(如果可以)。

回答by Kaz

In C, it is best to use enums for actual enumerations: when some variable can hold one of multiple values which can be given names. One advantage of enums is that the compiler can perform some checks beyond what the language requires, like that a switch statement on the enum type is not missing one of the cases. The enum identifiers also propagate into the debugging information. In a debugger, you can see the identifier name as the value of an enum variable, rather than just the numeric value.

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

Enumerations can be used just for the side effect of creating symbolic constants of integral type. For instance:

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

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

this practice is not that wide spread. For one thing, buffer_sizewill be used as an integer and not as an enumerated type. A debugger will not render 4096into buffer_size, because that value won't be represented as the enumerated type. If you declare some char array[max_buffer_size];then sizeof arraywill not show up as buffer_size. In this situation, the enumeration constant disappears at compile time, so it might as well be a macro. And there are disadvantages, like not being able to control its exact type. (There might be some small advantage in some situation where the output of the preprocessing stages of translation is being captured as text. A macro will have turned into 4096, whereas buffer_sizewill stay as buffer_size).

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

A preprocessor symbol lets us do this:

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

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

Note that various values from C's <limits.h>like UINT_MAXare preprocessor symbols and not enum symbols, with good reasons for that, because those identifiers need to have a precisely determined type. Another advantage of a preprocessor symbol is that we can test for its presence, or even make decisions based on its value:

请注意,来自 C 之<limits.h>类的各种值UINT_MAX是预处理器符号而不是枚举符号,这是有充分理由的,因为这些标识符需要具有精确确定的类型。预处理器符号的另一个优点是我们可以测试它的存在,甚至可以根据它的值做出决定:

#if ULONG_MAX > UINT_MAX 
/* unsigned long is wider than unsigned int */
#endif

Of course we can test enumerated constants also, but not in such a way that we can change global declarations based on the result.

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

Enumerations are also ill suited for bitmasks:

枚举也不适用于位掩码:

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

it just doesn't make sense because when the values are combined with a bitwise OR, they produce a value which is outside of the type. Such code causes a headache, too, if it is ever ported to C++, which has (somewhat more) type-safe enumerations.

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

回答by Jens

Note there are some differences between macros and enums, and either of these properties may make them (un)suitable as a particular constant.

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

  • enums are signed (compatible with int). In any context where an unsigned type is required (think especially bitwise operations!), enums are out.
  • if long long is wider than int, big constants won't fit in an enum.
  • The size of an enum is sizeof(int). For arrays of small values (up to say, CHAR_MAX) you might want a char foo[]rather than an enum foo[]array.
  • enums are integral numbers. You can't have enum funny_number { PI=3.14, E=2.71 }.
  • enums are a C89 feature; K&R compilers (admittedly ancient) don't understand them.
  • 枚举是有符号的(与 int 兼容)。在任何需要无符号类型的上下文中(尤其是按位运算!),枚举都被淘汰了。
  • 如果 long long 比 int 宽,则大常量将不适合枚举。
  • 枚举的大小是sizeof(int). 对于小值数组(比如CHAR_MAX),您可能需要一个char foo[]而不是enum foo[]数组。
  • 枚举是整数。你不能有enum funny_number { PI=3.14, E=2.71 }
  • 枚举是 C89 的特性;K&R 编译器(公认的古老)不理解它们。

回答by AnT

If macro is implemented properly (i.e it does not suffer from associativity issues when substituted), then there's not much difference in applicability between macro and enum constants in situations where bothare applicable, i.e. in situation where you need signed integer constants specifically.

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

However, in general case macros provide much more flexible functionality. Enums impose a specific type onto your constants: they will have type int(or, possibly, larger signed integer type), and they will always be signed. With macros you can use constant syntax, suffixes and/or explicit type conversions to produce a constant of any type.

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

Enums work best when you have a group of tightly associated sequential integer constants. They work especially well when you don't care about the actual values of the constants at all, i.e. when you only care about them having somewell-behaved unique values. In all other cases macros are a better choice (or basically the only choice).

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

回答by jxh

As a practical matter, there is little difference. They are equally usable as constants in your programs. Some may prefer one or the other for stylistic reasons, but I can't think of any technical reason to prefer one over the other.

作为一个实际问题,几乎没有区别。它们同样可用作程序中的常量。有些人可能出于文体原因更喜欢一个或另一个,但我想不出任何技术原因更喜欢一个。

One difference is that macros allow you to control the integral type of related constants. But an enumwill use an int.

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

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

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