21

我最近一直在使用大量的文件描述符,我一直想知道为什么它们被实现为整数?

这意味着它们很容易与其他整数混淆,并且没有上下文就无法知道它们是什么,它们指向什么,它们是否是开放的等等。

在 C 中,FILE是一个不透明的struct类型。许多人也将typedefstatus_t作为整数,因此它们的功能是显而易见的。似乎最好的办法是将它们实现为不透明类型,或者(例如在 C++ 中)作为可以处理某些实现的类,并清理namespace一点(调用pipe()open()看起来如此无害,并且在没有上下文的情况下,您正在管道或打开什么并不明显)。例如std::file_descriptor,使用构造函数/工厂函数来创建管道或打开文件等。

我希望这是本网站的主题;我试图将其表述为“为什么做出这个特定的决定? ”如果有人知道它更适合的地方,请告诉我。

4

3 回答 3

27

历史,如果没有别的。回到 1970 年代,使用它可能看起来不是问题int(事实上,该值是固定大小表的索引)。后来,将其更改为另一种类型会破坏代码。

于 2013-07-22T13:18:56.227 回答
19

你的问题可以分为两部分:

为什么是 POSIX 文件描述符int

就像已经建立的工具和库中的大多数东西一样,答案可能是历史原因。詹姆斯的回答指出了这一点。

使文件描述符不透明可能是一个好主意,但不是因为您提到的原因。使类型不透明有利于根据某些参数具有不同的类型。例如,在某些系统上,您可能需要long longas 文件描述符。然而,正如它似乎发生的那样,没有人同时需要 20 亿个打开的文件,因此没有人关心解决这个不存在的问题。

另一方面,这样的事情typedef int file_descriptor;不会解决您上面提到的任何问题:

这意味着它们很容易与其他整数混淆......

如果你混淆了你的变量,我有坏消息要告诉你。编译器也不会帮助您,因为file_descriptorint是相同的类型,因此允许对另一个进行任何操作。

...并且没有上下文就无法知道它们是什么,它们指向什么,它们是否是开放的,等等。

你也不能这样做FILE。这就是为什么你有一些函数可以查询你寻找的信息并返回它,就像FILE. typedef输入类型不会给你任何额外的信息。

为什么 POSIX 没有 C++ 包装器呢?

简而言之,因为除了微软,没有一个操作系统开发者会爱上 C++。Windows 甚至都不是 POSIX,因此微软没有希望尝试改进任何 POSIX。其他兼容 POSIX 的操作系统将 C API 作为事实上的系统编程语言(部分原因是正如nm 所说,几乎所有语言都可以绑定到 C)。

事实上,C++ 在应用程序开发人员中很流行,但在系统程序员中并不流行。POSIX 委员会似乎对 C++ 也不是特别感兴趣。这就是为什么您会看到 C 并且只有 C 解决方案和关于 POSIX API 的参数。另请注意,创建 POSIX 是为了特别是标准化 UNIX 的接口,它是用 C 编写的,其最重要的后代之一 Linux 也与 C 密切相关。

于 2013-07-22T14:49:28.067 回答
2

Unix 接口是用 C 语言描述的,但同样重要的是系统有一个 ABI,而不仅仅是一个 API。

特定于编程语言的奇特数据结构使 ABI 复杂化。在 ABI 级别,您只有低级别的数据类型,如“32 位无符号整数”及其简单聚合。

话虽如此,Unix 接口确实使用了pid_t诸如此类之类的类型,那么为什么不将这些 typedef 之一用于文件描述符呢?

文件描述符具有某些众所周知的值,当打开一个新的文件描述符时,总是使用可用的最小正值。文件描述符值有效地充当描述符表中的数组索引,并且设计是故意的。程序员的文件描述符模型是它们在内核中有类似数组的结构。该dup2函数实际上可以将文件描述符从一个插槽复制到另一个插槽。这样的数组索引也可能是int,对于信号错误具有负值。

C typedefs 不购买额外的类型检查,但它们确实带来了一点可读性和抽象性:独立于特定的整数类型。一个fd_t类型可以是int一个系统上的一个和long另一个系统上的一个。但是由于int几十年前已经发展到几乎无处不在的 32 位宽,因此没有真正需要为了能够在同名下使其更宽而对其进行抽象。一个程序需要超过 20 亿个打开的文件描述符是非常不寻常的。

相比之下,如果使用纯文本int而不是pthread_t.

int对于 Windows Socket API 的设计者来说,描述符确实难以接受,他们发明了SOCKETtypedef,其值不是可用的最低正整数;只是导致便携性烦恼的怪癖之一。但是,依赖这些描述符的代码存在真正的语义差异,这些描述符是一个范围内的小值,要么不起作用,要么表现低效。

有一些历史上的 Unix 实例已被修改为int用一些 typedef 替换普通类型。例如,在一个accept函数中,远程地址结构的大小过去只是int. 然后就变成了socklen_t。没有存在的技术需求socklen_t;它被发明为一种创可贴的解决方案,以弥合使用传统系统的系统int与维护者热心改变使用论点的系统之间的差异size_t。虽然这两种类型导致相同的 ABI,但没有问题,直到具有 64 位size_t和 32 位的系统int

于 2013-07-22T18:51:27.567 回答