【问题标题】:Peculiar use of C macrosC 宏的特殊用途
【发布时间】:2012-07-08 12:11:21
【问题描述】:

阅读C库的sockets接口的代码,发现如下:

/* Types of sockets.  */
enum __socket_type
{
   SOCK_STREAM = 1,     /* Sequenced, reliable, connection-based
               byte streams.  */
#define SOCK_STREAM SOCK_STREAM
   SOCK_DGRAM = 2,      /* Connectionless, unreliable datagrams
               of fixed maximum length.  */
#define SOCK_DGRAM SOCK_DGRAM
...

这个“成语”在 bits/socket.h 中使用。我只是好奇,这些宏的用途是什么?

【问题讨论】:

    标签: c enums constants preprocessor


    【解决方案1】:

    这些常量过去只是#defines,所以您看到的内容可能是为了防止您意外混合新旧头文件。使用enum 定义常量的一个优点是enum 成员往往在调试器中可用,而#define 宏不可用。

    如果您(不小心)包含其他一些也尝试使用#define SOCK_STREAM 的头文件,您将收到编译器警告,而不是默默地使用可能不正确的值。

    更新

    查看glibc git repo,我找到了添加#defines 的特定提交,并带有以下评论:

    * sysdeps/generic/socketbits.h: Also make SOCK_* constants available
    as macros so that #ifdef works.
    * sysdeps/unix/sysv/linux/socketbits.h: Likewise.
    

    你有它。

    【讨论】:

    • 问:这不是我说的;)?
    【解决方案2】:

    它是“枚举”的 C 等价物。

    逻辑套接字类型“流”(SOCK_STREAM)对应二进制值“1”。 “数据报”(SOCK_DGRAM)是类型“2”。等等。

    “套接字”是在“枚举”成为 C 语言的一部分之前发明的。

    上述成语允许您在代码中使用“SOCK_STREAM”(例如);它还允许您使用“#ifndef SOCK_STREAM”(这在某些遗留程序中可能很重要)。

    【讨论】:

      【解决方案3】:

      历史系统使用宏并且没有这样的枚举。

      旧版本的 POSIX/Single Unix(例如 SUSv3)要求 SOCK_xxx 是宏。这意味着这些常量可以在预处理器指令中使用(例如#ifdef SOCK_DGRAM)。这有时对于在构建时检查系统是否支持非标准套接字类型很有用。

      较新的标准(例如SUSv4)放宽了对系统的这一要求:SOCK_xxx 常量可以是任何类型的symbolic constants。这包括预处理器宏,但也包括任何其他类型的生成常量表达式的定义(适用于静态初始化程序和其他需要常量表达式的上下文),例如枚举常量。

      您正在查看的实现符合 SUSv3(和 SUSv4,SUSv3 合规性意味着在这方面 SUSv4 合规性)。仅定义枚举而不定义常量的实现将符合 SUSv4 但不符合 SUSv3。

      定义枚举的优点是,如果在不要求 1 的上下文中使用 SOCK_xxx 常量或在 SOCK_xxx 值的情况下使用任意整数时,它允许编译器给出适当的反馈预计。

      许多类似的常量集也是如此。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-01
        • 2011-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多