为什么 C 语言程序员更偏爱使用宏定义一组常量, 而不使用枚举? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
0littleboy
V2EX    C

为什么 C 语言程序员更偏爱使用宏定义一组常量, 而不使用枚举?

  •  1
     
  •   0littleboy 2023-04-26 16:49:39 +08:00 3852 次点击
    这是一个创建于 903 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如:

    /* open-only flags */ #define O_RDONLY 0x0000 /* open for reading only */ #define O_WRONLY 0x0001 /* open for writing only */ #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 

    这些定义成枚举,可读性不是更强吗

    16 条回复    2023-04-28 10:22:49 +08:00
    pursuer
        1
    pursuer  
       2023-04-26 17:12:04 +08:00
    我个人来说,一个变量可以是多组常量的组合的时候,用宏比较方便,然后就习惯用宏了
    CodeCore
        2
    CodeCore  
       2023-04-26 17:39:45 +08:00
    claude 的回答:
    使用宏定义一组常量而不使用枚举的主要原因有:
    1. 兼容性:宏定义只是简单的文本替换,可以在任何标准 C/C++中使用,而枚举是 C 语言特有的类型,在 C++中作为一种 scoped enum 使用。所以如果要确保代码在各种编译器和语言版本中都能编译通过,宏定义会更具兼容性。
    2. 前向声明:对于枚举类型,在使用前必须将其定义,而宏定义可以在使用前就声明。这在 header 文件中定义常量时比较重要,可以先声明使用宏定义的常量,然后在源文件中定义具体值。
    3. 类型安全:枚举有着严格的类型检查,只能用于和枚举类型兼容的场合。而宏定义只是简单替换,没有严格的类型,可以用于任何场合。这在一些特殊情况下会更灵活,但也可能引入 bug 。
    4. 值的定义:枚举中的值必须是整数,而宏定义的值可以是任何文本,这在定义一些特殊常量时可能会更有用。
    5. 可读性:宏定义中的值只是简单的文本替换,而不像枚举那样清晰地定义一个新类型和值。所以从可读性而言,枚举的表现会更好。
    所以综上,当需要高兼容性、前向声明以及特殊值定义,可以考虑使用宏定义。其他时间优先考虑使用枚举,以获取类型安全检查、更清晰的语义和更好的可读性。也可以两者结合使用,根据具体情况选择。
    blindie
        3
    blindie  
       2023-04-26 18:05:26 +08:00
    // Type of animals
    #define TIGER 0
    #define CAT 1
    #define HUMAN 2

    enum animal {
    TIGER = 0,
    CAT,
    HUMAN
    }
    可读性其实是差不多的。至于为啥 C 语言程序员更偏爱用宏可能是大家都在用入乡随俗?比如我就从来没在 C 里面写过枚举,没看到这个贴子之前我甚至都没想过这回事。
    xtreme1
        4
    xtreme1  
       2023-04-26 18:10:54 +08:00
    K&R C 一路沿袭下来的习惯吧, 枚举是 C89 的特性
    icyalala
        5
    icyalala  
       2023-04-26 18:14:04 +08:00
    主要是历史原因,最初的 K&R 版本的 C 还不支持 enum 。
    后来 ANSI C 也没明确 enum 的长度,而是可以由编译器决定。
    另外如果常量是 flag ,需要用 or 来连接的话,用 enum 也不合适。
    junyee
        6
    junyee  
       2023-04-26 19:27:54 +08:00
    我说一点:

    宏可以嵌套宏,
    但是宏不能嵌套枚举常量。
    klwha
        7
    klwha  
       2023-04-26 20:13:33 +08:00
    @icyalala 这个是不是和 c++里到目前为止还是很少见 constexpr 和 consteval 有人用一样?
    artnowben
        8
    artnowben  
       2023-04-26 21:02:32 +08:00
    通常 enum 的值是从 0 开始递增的;而宏的值是可以任意的,例如按 bit 位置 1 。

    例子:
    #define HTTP_F_CONTENT_LENGTH_AUTO 0x1
    #define HTTP_F_CONTENT_LENGTH 0x2
    #define HTTP_F_TRANSFER_ENCODING 0x4
    #define HTTP_F_CLOSE 0x8

    https://github.com/baidu/dperf/blob/main/src/http_parse.h
    weyou
        9
    weyou  
       2023-04-26 23:47:32 +08:00
    @blindie 枚举类型可以 typedef 成一个类型用于变量,特别是作为函数参数, 一看就知道参数值的范围。 这种情况下可读性要比宏好的多。
    LXGMAX
        10
    LXGMAX  
       2023-04-27 09:25:31 +08:00
    常量具有同一特征且值不需要指定:
    enum
    JANUARY = 0,
    FEBRUARY,
    MARCH
    ...

    反之
    #define GPIOA 0x080001
    #define GPIOB 0x080002
    macha
        11
    macha  
       2023-04-27 10:16:42 +08:00
    主要还是习惯,尤其是定义错误码的时候,用枚举很变扭
    nmap
        12
    nmap  
       2023-04-27 11:27:23 +08:00
    历史传承
    tomychen
        13
    tomychen  
       2023-04-27 14:07:46 +08:00
    感觉是历史遗留问题

    enum 是 C89 后才有的特性

    再就是,不是所有常量都是顺序的数值+1
    ssw2
        14
    ssw2  
       2023-04-27 17:57:27 +08:00
    C 语言枚举有定义域的坑,用起来远不如宏定义清晰
    noroot
        15
    noroot  
       2023-04-28 10:20:19 +08:00
    看情况,现在一般情况应该是如果可以用枚举替代的话更建议用枚举,因为可以利用类型检查来规避一些错误。为什么更喜欢用宏大概是历史惯性。
    noroot
        16
    noroot  
       2023-04-28 10:22:49 +08:00
    用枚举好像存在一个这样的问题:一些项目会利用编译器的特性指定了枚举的底层大小,这时候超过这个大小的枚举值可能会 UB 。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5371 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 06:58 PVG 14:58 LAX 23:58 JFK 02:58
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86