What makes the best constant in C, macro or enumeration?

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 one of them? Is this somehow related to the compiler level or not?

+31
c macros enums
Jun 15 '13 at 16:05
source share
6 answers

In terms of readability, enumerations create better constants than macros, since related values ​​are grouped together. In addition, enum defines a new type, so it would be easier for readers of your program to find out what can be passed to the corresponding parameter.

Comparison

 #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's much easier to read code like this.

 void calendar_set_weekday(Weekday wd); 

than that

 void calendar_set_weekday(int wd); 

because you know which constants must pass.

+30
Jun 15 '13 at 16:10
source share

A macro is a preprocessor, and compiled code has no idea about the identifiers you create. They are already replaced by the preprocessor before the code gets into the compiler. An enumeration is a compile-time object, and compiled code stores complete information about the symbol, which is available in the debugger (and other tools).

Prefer enumerations (when you can).

+18
Jun 15 '13 at 16:09
source share

Note that there are some differences between macros and enumerations, and any of these properties can make them (un) suitable as a specific constant.

  • lists are signed (compatible with int). In any context where an unsigned type is required (think, in particular, bitwise operations!), Enumerations are missing.
  • if long long is wider than int, large constants will not fit into the enumeration.
  • The size of the enumeration is sizeof(int) . For arrays of small values ​​(like CHAR_MAX ), you might need char foo[] rather than an enum foo[] array.
  • enumerations are integers. You cannot have enum funny_number { PI=3.14, E=2.71 } .
  • enumerations are a function of C89; K & R compilers (admittedly ancient) do not understand them.
+9
Jun 15 '13 at 17:50
source share

In C, it is best to use enumerations for actual enumerations: when a variable can contain one of several values ​​to which names can be assigned. One of the advantages of enums is that the compiler can perform some checks, in addition to what the language requires, for example, that the switch statement for an enum type does not skip one of these cases. Enumeration identifiers also apply to debug information. In the debugger, you can see the identifier name as the value of the enum variable, and not just a numerical value.

Enumerations can only be used as a side effect of creating symbolic constants of an integral type. For example:

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

this practice is not so widespread. First, buffer_size will be used as an integer, not an enumerated type. The debugger will not map 4096 to buffer_size because this value will not be represented as an enumerated type. If you declare multiple char array[max_buffer_size]; , then the sizeof array will not display as buffer_size . In this situation, the enumeration constant disappears at compile time, so it can also be a macro. And there are flaws, such as the inability to control its exact type. (In some situations, there may be some slight advantage when the output of the translation preprocessing stages is fixed as text. The macro will turn into 4096, while buffer_size will remain as buffer_size ).

The preprocessor symbol allows us to do this:

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

Note that various values ​​from C <limits.h> , such as UINT_MAX , are preprocessor characters, not enumerated characters, which is a good reason for this, since these identifiers must be of a precisely defined type. Another advantage of the preprocessor symbol is that we can check its presence or even make decisions based on its value:

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

Of course, we can also check the constants listed, but not so that we can modify global declarations based on the result.

Enumerations are also poorly suited for bitmaxes:

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

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

+9
Jun 15 '13 at 18:38
source share

If the macro is implemented correctly (i.e., it does not suffer from associativity problems when replacing), then there is not much difference in applicability between the macro and enum constants in situations where they are applicable, i.e. in a situation where you need fixed integer constants.

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

Enums work best when you have a group of closely related consecutive 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 that they have some good values. In all other cases, macros are the best choice (or, basically, the only choice).

+4
Jun 15 '13 at 18:12
source share

In practical terms, there are few differences. They are equally useful as constants in your programs. Some may prefer one or the other for stylistic reasons, but I cannot come up with any technical reasons to prefer each other.

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

 #define X 100L enum { Y = 100L }; printf("%ld\n", X); printf("%d\n", Y); /* Y has int type */ 
+2
Jun 15 '13 at 16:31
source share



All Articles