读取C库的套接字接口的代码,我发现了这个:
/* 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
...
这个“成语”遍布bit / socket.h。我只是很好奇,那些宏的目的是什么?
答案 0 :(得分:6)
这些常量过去只是#define
s,所以你所看到的可能就是保护你不会意外地混合旧的和新的头文件。使用enum
定义常量的一个优点是enum
成员往往在调试器中可用,而#define
宏则不可用。
如果您(意外地)包含了一些其他尝试#define SOCK_STREAM
的头文件,您将收到编译器警告,而不是静默使用可能不正确的值。
通过glibc git repo查看,我发现了添加#define
s的具体提交,并附有以下评论:
* sysdeps/generic/socketbits.h: Also make SOCK_* constants available
as macros so that #ifdef works.
* sysdeps/unix/sysv/linux/socketbits.h: Likewise.
你有它。
答案 1 :(得分:2)
这是“enum”的C等价物。
逻辑套接字类型“stream”(SOCK_STREAM)对应于二进制值“1”。 “数据报”(SOCK_DGRAM)是类型“2”。等
“套接字”是在“enum”成为C语言的一部分之前发明的。
上述习语允许您在代码中使用“SOCK_STREAM”(例如);它还允许您使用“#ifndef SOCK_STREAM”(这在某些遗留程序中可能很重要)。
答案 2 :(得分:1)
历史系统使用宏并且没有这样的枚举。
旧版本的POSIX / Single Unix(例如SUSv3)强制SOCK_xxx
为宏。这意味着这些常量可以用在预处理程序指令中(例如#ifdef SOCK_DGRAM
)。这有时可以在构建时检查系统是否支持非标准套接字类型。
较新的标准(例如SUSv4)放宽了对系统的要求:SOCK_xxx
常量可以是任何类型的symbolic constants。这包括预处理器宏以及产生常量表达式的任何其他类型的定义(适用于静态初始化器和需要常量表达式的其他上下文),例如枚举常量。
您正在查看的实施符合SUSv3(SUSv4,SUSv3合规性意味着在这方面符合SUSv4)。仅定义枚举而不是常量的实现将符合SUSv4但不符合SUSv3。
定义枚举的优点是,如果在不调用一个的上下文中使用SOCK_xxx
常量,或者如果使用任意整数,它允许编译器提供适当的反馈。预计会有SOCK_xxx
值。
许多类似的常量也是如此。