[英]Correct way to write X bytes to a file descriptor where X is a unsigned 64-bit integer
Consider the following C function: 考虑以下C函数:
static void
write_buf_to_disk(int fd, void *buf, __u64 size) {
const char* char_buf = buf;
__u64 written = 0;
while (size > 0) {
ssize_t res = write(fd, char_buf, size);
if (res == -1) {
if (errno == EINTR) {
// Write interrupted before anything written.
continue;
}
err(EXIT_FAILURE, "write");
}
written += res;
char_buf += res;
size -= res;
}
}
The function reads bytes out of buf
until the requested number of bytes have been written. 该函数从
buf
读取字节,直到已写入请求的字节数为止。 The type of size
is out of my control, and must be a __u64
. size
类型超出了我的控制范围,必须为__u64
。
I don't think this is portable due to friction between ssize_t
and __u64
. 由于
ssize_t
和__u64
之间的摩擦,我认为这不是可移植的。
ssize_t
comes from a rather vague POSIX extension which AFAICS guarantees to be: ssize_t
来自一个模糊的POSIX扩展,AFAICS保证它是:
size_t
size_t
大小相同 So in theory ssize_t
could be (unlikely, I know) 512 bits wide, meaning that written += res
invokes undefined behaviour. 因此,从理论上讲,
ssize_t
可能是(不太可能,我知道)512位宽,这意味着written += res
调用未定义的行为。
How does one guard against this in a portable fashion? 如何以一种可移植的方式防止这种情况发生?
res
will be no higher than write
's third argument, so all you have to do is constrain the 3rd argument of write
to be no larger than the largest positive value that res
( ssize_t
) can store. res
将不高于write
的第三个参数,因此,所有你需要做的就是限制的第三个参数write
到不低于最大正值大res
( ssize_t
)可以存储。
In other words, replace 换句话说,替换
ssize_t res = write(fd, char_buf, size);
with 与
size_t block_size = SSIZE_MAX;
if (block_size > size)
block_size = size;
ssize_t res = write(fd, char_buf, block_size);
You get: 你得到:
static void
write_buf_to_disk(int fd, void *buf, __u64 size) {
const char* char_buf = buf;
size_t block_size = SSIZE_MAX;
while (size > 0) {
if (block_size > size)
block_size = size;
ssize_t res = write(fd, char_buf, block_size);
if (res == -1) {
if (errno == EINTR)
continue;
err(EXIT_FAILURE, "write");
}
char_buf += res;
size -= res;
}
}
In 在
ssize_t res = write(fd, buf, size);
even if ssize_t
would be 512 bits wide, as you suggested, the compiler promotes the result of write
(64 bits) to that size. 即使您建议的
ssize_t
为512位宽,编译器也会将write
结果(64位)提升为该大小。 So the comparison would still work. 因此,比较仍然可以进行。
In 在
written += res;
the compiler would give you a warning, but 64 bits to count the number of bytes written is really gigantic (~10 19 bytes max). 编译器会警告您,但是64位来计数写入的字节数确实是巨大的(最多10个19字节)。 So you're unlikely to miss any write even though the addition is from a 512 bits to a 64 bits.
因此,即使从512位增加到64位,您也不会丢失任何写入。
You could also assign the size to a ssize_t
at the beginning of the function 您也可以在函数开始时将大小分配给
ssize_t
write_buf_to_disk(int fd, void *buf, __u64 size64) {
ssize_t size = size64;
that would make the rest of the body in line with the system functions. 这将使身体的其余部分与系统功能保持一致。
The C11 standard says (7.19): C11标准说(7.19):
The types used for
size_t
andptrdiff_t
should not have an integer conversion rank greater than that ofsigned long int
unless the implementation supports objects large enough to make this necessary.除非实现支持足够大的对象以使其成为必需,否则用于
size_t
和ptrdiff_t
的类型的整数转换等级不应大于有signed long int
的整数转换等级。
So size_t
and ssize_t
are unlikely to be 512 bits, unless you run on a 512-bit processor. 因此,除非您在512位处理器上运行,否则
size_t
和ssize_t
不太可能是512位。
Right now you are extremely likely not to need more than 64 bits for any memory or disk size. 现在,你极有可能并不需要任何内存或磁盘大小超过64位。 That limits the amount of data you can have in a
write
statement. 这限制了您在
write
语句中可以拥有的数据量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.