6

阅读 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
...

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

4

3 回答 3

7

这些常量过去只是#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.

你有它。

于 2012-07-09T04:53:53.427 回答
1

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

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

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

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

于 2012-07-09T04:53:09.683 回答
0

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

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

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

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

定义枚举的优点是,如果SOCK_xxx在不需要一个常量的上下文中使用常量,或者在SOCK_xxx预期值的地方使用任意整数,它允许编译器给出体面的反馈。

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

于 2016-09-21T21:54:11.297 回答