write(2) 总是写小于或等于 SSIZE_MAX 吗?

Will write(2) always write less than or equal to SSIZE_MAX?

write(2) 的函数签名是 ssize_t write(int fd, const void *buf, size_t count)。一般来说,size_t的最大值大于ssize_t的最大值。这是否意味着 write 实际可以写入的数据量实际上是 SSIZE_MAX 而不是 SIZE_MAX?如果不是这种情况,当写入的字节数大于 SSIZE_MAX 溢出时会发生什么情况?

我基本上想知道 write 写入的数据量是否受 SSIZE_MAXSIZE_MAX 的限制。

是的,在一次写入调用中可以写入的数据量限于 ssize_t 中可以保存的数据量。有关说明,请参阅 the relevant glibc documentation page。引用该页面,"Your program should always call write in a loop, iterating until all the data is written."(强调)该页面还阐明了 ssize_t 用于表示可以在单个操作中读取或写入的块的大小。

类型 ssize_t 由 POSIX 定义为签名类型,能够存储至少 32767 (_POSIX_SSIZE_MAX),没有其他保证。所以它的最大值可以小于size_t的最大值。

ssize_t的POSIX定义:

ssize_t

Used for a count of bytes or an error indication.

因此您请求写入的字节数可能大于 ssize_t 可以容纳的字节数。在这种情况下,POSIX 将其留给实施。

来自 write() 的 POSIX 规范:

ssize_t write(int fildes, const void *buf, size_t nbyte);

If the value of nbyte is greater than {SSIZE_MAX}, the result is implementation-defined.

write() 的 POSIX 规范说:

If the value of nbyte is greater than {SSIZE_MAX}, the result is implementation-defined.

因此,任何写入超过 SSIZE_MAX 字节的尝试都会导致 POSIX 未强制执行但必须由系统记录的行为(它是实现定义的,而不是未定义,行为)。但是,不同的系统可能会以不同的方式处理它,并且没有什么可以阻止一个系统报告错误(可能 errno 设置为 EINVAL),而另一个系统写入 SSIZE_MAX 字节并报告,留下它应用程序在其余部分上重试,其他系统可能具有创造性并以不同的方式做事。

如果你有一个 64 位系统,SSIZE_MAX 可能比世界上最大的单一数据中心的磁盘数量 space 大(可能大一个数量级)或更多,甚至考虑到 NSA 和 Google),所以你不太可能 运行 遇到真正的问题,但在 32 位系统上,你可以很容易地拥有超过 2 space 的 GiB,如果 ssize_t 是 32 位,你必须处理所有这些。 (在 Mac OS X 10.10.3 上,32 位构建具有 4 字节 size_tssize_t,至少在默认情况下是这样。)