[英]Choosing between enum or define in C?
我注意到libc
中的大多數預定義值都是使用#define
指令編寫的。 例如, whence
參數在fseek
中獲取一個int
(據我所知) enum
本來會更好。 有很多這樣的例子顯然應該出於某種原因(除了后兼容性問題)。
所以我想知道在哪種情況下使用#define
更好,而enum
是一種更容易被發現的類型安全的替代品 。
作為一個實際例子,考慮一個表示輸入/輸出通道的typedef
,因為它可能是內核的情況。 gpio可以在輸入或輸出中配置。 在這里使用enum
指令是否值得?
typedef struct gpio {
size_t port;
size_t bit;
enum { DIR_INPUT, DIR_OUTPUT } direction; // or `bool`?
bool value;
} gpio;
請注意, enum
可以用三種不同的方式實現:
i)類型:
typedef enum gpio_direction {
DIR_OUTPUT
DIR_INPUT
} gpio_direction;
ii)全球枚舉
enum gpio_direction {
DIR_OUTPUT
DIR_INPUT
} gpio_direction;
iii)匿名枚舉(如我的例子所示)。
有很多這樣的例子顯然應該存在是有原因的
一個原因是沒有可移植的方法來從匯編代碼中引用C enum
。 低級代碼通常(通常仍然是)用匯編語言編寫,因此低級代碼使用的常量將由#define
而不是enum
指定。
另一個原因是成語if (verbosity & WAKE_THE_NEIGHBOURS)
,其中#defined
值用於指定位位置。
所以我想知道在哪種情況下使用#define更好,而枚舉是一種類型安全的替代方案,更容易被發現
在所有其他情況下,我(今天 - 使用#define
也有點傳統)使用enum
,因此if (verbosity == RED)
會引發警告(如果你使用例如gcc
with -Wall
)。
雖然人們可能應該使用其他可用的解決方案,但仍然存在需要宏的情況。 有些是歷史原因,但今天仍有其他原因。
例如,你提到了fseek
的whence
參數(即SEEK_SET
, SEEK_CUR
和` SEEK_CUR
)。 這些(由於歷史原因)被指定為標准中的宏 - 因此實現者必須將它們定義為完全符合的宏,一些邪惡的程序員可以編寫(並責怪庫的后果):
#include <stdio.h>
#ifndef SEEK_CUR
int evil = *(int*)0;
#endif
但據我所知,他們沒有理由不寫:
enum __WHENCE_T {
__SEEK_CUR,
__SEEK_END,
__SEEK_SET
};
#define SEEK_CUR __SEEK_CUR
#define SEEK_END __SEEK_END
#define SEEK_SET __SEEK_SET
另一個歷史原因是編譯器在使用宏時可能產生了更高效的代碼。 當時寫的代碼可能仍然存在並且包含當時工作得更好的構造(並且今天仍然很好用)。
現代的原因是你需要使用C編譯器之外的值。 例如,如果您想在匯編程序代碼(或其他語言)中使用該值。 您需要做的就是確保標題不會擴展為某些內容(包含C代碼),除非它是使用C編譯器編譯的。 例如:
#define NUMBER 42
#ifdef __STDC__
extern int variable;
int function(void);
#endif
如果包含在匯編程序中,宏NUMBER
仍然可以擴展(並擴展到與C程序相同的東西)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.