Choosing between an enumeration or a definition in C?

I noticed that most of the predefined values ​​in libc are written using #define directives. For example, the whence parameter takes an int in fseek , where (to my knowledge) enum would be better. There are many examples like this that obviously should exist for some reason (other than backward compatibility issues).

So I'm wondering in which case it is better to use #define , while enum is a type alternative that is more easily detectable .

As a practical example, consider a typedef representing an input / output channel, as it would be in the case of the kernel. Gpio can be configured either at the input or output. Should I use the enum directive here?

 typedef struct gpio { size_t port; size_t bit; enum { DIR_INPUT, DIR_OUTPUT } direction; // or `bool`? bool value; } gpio; 

Note that enum can be implemented in three different ways:

i) Type:

 typedef enum gpio_direction { DIR_OUTPUT DIR_INPUT } gpio_direction; 

ii) Global listing

 enum gpio_direction { DIR_OUTPUT DIR_INPUT } gpio_direction; 

iii) Anonymous enum (as shown in my example).

+7
c enums casting
source share
2 answers

There are many examples that should be obvious for a reason.

One reason is that there is no portable way to reference C enum from assembler code. Low-level code was usually (and often still) written in assembly, so the constants used by this low-level code will be #define , not enum .

Another reason is idiom if (verbosity & WAKE_THE_NEIGHBOURS) , where the value #defined used to indicate the position of the bit.

So I'm wondering in which case it is better to use #define, whereas enum is an alternative to types that are more easily detectable.

In all other cases, I would (today - using #define also somewhat traditionally) use enum , so if (verbosity == RED) will raise a warning (if you use eg gcc with -Wall ).

+5
source share

While other solutions should probably be used, where they are available, there are still situations where macros are required. Some of them are historical reasons, but there are still reasons.

For example, you specify the whence argument to fseek (i.e., SEEK_SET , SEEK_CUR and `SEEK_END). These (for historical reasons) are indicated as macros in the standard, so the developer must define them as fully compatible macros, some kind of evil programmer could write (and blame the library for the consequences):

 #include <stdio.h> #ifndef SEEK_CUR int evil = *(int*)0; #endif 

But as far as I see, there is no reason why they could not write:

 enum __WHENCE_T { __SEEK_CUR, __SEEK_END, __SEEK_SET }; #define SEEK_CUR __SEEK_CUR #define SEEK_END __SEEK_END #define SEEK_SET __SEEK_SET 

Another historical reason is that the compiler could create more efficient code when using macros. The code that was written then may still be around and contain constructs that worked better then (and still work pretty god).

Modern reasons: if you need to use values ​​outside the C compiler. For example, as mentioned, if you want to use a value in assembler code (or in some other language). All you have to do is make sure the header does not expand to something (containing the C code) if it is not compiled with the C compiler. For example:

 #define NUMBER 42 #ifdef __STDC__ extern int variable; int function(void); #endif 

if it is enabled from assembler, the NUMBER macro will expand (and expand to the same as for C programs).

+3
source share

All Articles