系统调用的基本原理允许size_t的请求,但只有ssize_t的结果?

时间:2021-12-09 17:03:16

Consider:

考虑:

ssize_t write(int fd, const void *buf, size_t count);

The result has to be signed to account for -1 on error, etc., and is thus ssize_t. But why then allow for the request to be an unsigned amount (twice as large) when the result of asking for more than ssize_t is undefined?

结果必须在错误等情况下签名为-1,因此是ssize_t。但是,当要求超过ssize_t的结果未定义时,为什么允许请求为无符号数量(两倍大)?

Is there a significant optimization in the kernel by virtue of not checking for signedness of the count parameter? Or something else?

由于没有检查计数参数的有效性,内核是否有重大的优化?或者是其他东西?

4 个解决方案

#1


6  

According to the documentation for ssize_t write(int fildes, const void *buf, size_t nbyte)

根据ssize_t写的文档(int fildes,const void * buf,size_t nbyte)

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

如果nbyte的值大于{SSIZE_MAX},则结果是实现定义的。

So each particular implementation may handle this situation differently. I would not be surprised if some implementations simply set EFBIG.

因此,每个特定实现可以不同地处理这种情况如果某些实现只是设置EFBIG,我不会感到惊讶。

As for the rationale, perhaps size_t is simply the best type to represent the size of the buffer, semantically? It states that this argument is a nonnegative size, and nothing else.

至于基本原理,也许size_t只是表示缓冲区大小的最佳类型,从语义上来说呢?它声明这个论证是一个非负的大小,没有别的。

#2


5  

I think it's nice, since size_t is the type of the value returned by the sizeof operator, this allows calls like this:

我认为这很好,因为size_t是sizeof运算符返回的值的类型,这允许这样的调用:

char buffer[1 << 20];
ssize_t wrote;

wrote = write(fd, buffer, sizeof buffer);

If the function took the signed version, a cast would be required. Also, as others have pointed out, semantically functions like these cannot accept a negative value, so it doesn't make a lot of sense to accept them.

如果函数采用签名版本,则需要进行强制转换。此外,正如其他人所指出的那样,语义上这些函数不能接受负值,因此接受它们并没有多大意义。

#3


2  

By making the parameter unsigned it removes the need for the function to check for nonsensical negative requests.

通过使参数无符号,它不需要函数来检查无意义的否定请求。

#4


1  

write can only write from a single contiguous array of unsigned char, which cannot be larger than PTRDIFF_MAX, which is (on all real-world POSIX systems, and perhaps this is required by POSIX too...?) equal to SIZE_MAX/2. Thus passing a value which would be negative if interpreted as a signed value is a programming error to begin with - the passed size does not agree with the available space in the buffer.

write只能从一个连续的无符号字符数组中写入,这个字符不能大于PTRDIFF_MAX,它是(在所有真实的POSIX系统上,也可能是POSIX所需要的......?)等于SIZE_MAX / 2。因此,如果解释为带符号值,则传递一个为负的值是一个编程错误 - 传递的大小与缓冲区中的可用空间不一致。

In theory readv and writev could perform IO operations larger than SIZE_MAX/2 by repeating the same iov buffers multiple times in the array, but if I remember correctly, they're specified to fail if the total size would be greater than SSIZE_MAX.

理论上,readv和writev可以通过在数组中多次重复相同的iov缓冲区来执行大于SIZE_MAX / 2的IO操作,但是如果我没记错的话,如果总大小将大于SSIZE_MAX,则指定它们失败。

#1


6  

According to the documentation for ssize_t write(int fildes, const void *buf, size_t nbyte)

根据ssize_t写的文档(int fildes,const void * buf,size_t nbyte)

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

如果nbyte的值大于{SSIZE_MAX},则结果是实现定义的。

So each particular implementation may handle this situation differently. I would not be surprised if some implementations simply set EFBIG.

因此,每个特定实现可以不同地处理这种情况如果某些实现只是设置EFBIG,我不会感到惊讶。

As for the rationale, perhaps size_t is simply the best type to represent the size of the buffer, semantically? It states that this argument is a nonnegative size, and nothing else.

至于基本原理,也许size_t只是表示缓冲区大小的最佳类型,从语义上来说呢?它声明这个论证是一个非负的大小,没有别的。

#2


5  

I think it's nice, since size_t is the type of the value returned by the sizeof operator, this allows calls like this:

我认为这很好,因为size_t是sizeof运算符返回的值的类型,这允许这样的调用:

char buffer[1 << 20];
ssize_t wrote;

wrote = write(fd, buffer, sizeof buffer);

If the function took the signed version, a cast would be required. Also, as others have pointed out, semantically functions like these cannot accept a negative value, so it doesn't make a lot of sense to accept them.

如果函数采用签名版本,则需要进行强制转换。此外,正如其他人所指出的那样,语义上这些函数不能接受负值,因此接受它们并没有多大意义。

#3


2  

By making the parameter unsigned it removes the need for the function to check for nonsensical negative requests.

通过使参数无符号,它不需要函数来检查无意义的否定请求。

#4


1  

write can only write from a single contiguous array of unsigned char, which cannot be larger than PTRDIFF_MAX, which is (on all real-world POSIX systems, and perhaps this is required by POSIX too...?) equal to SIZE_MAX/2. Thus passing a value which would be negative if interpreted as a signed value is a programming error to begin with - the passed size does not agree with the available space in the buffer.

write只能从一个连续的无符号字符数组中写入,这个字符不能大于PTRDIFF_MAX,它是(在所有真实的POSIX系统上,也可能是POSIX所需要的......?)等于SIZE_MAX / 2。因此,如果解释为带符号值,则传递一个为负的值是一个编程错误 - 传递的大小与缓冲区中的可用空间不一致。

In theory readv and writev could perform IO operations larger than SIZE_MAX/2 by repeating the same iov buffers multiple times in the array, but if I remember correctly, they're specified to fail if the total size would be greater than SSIZE_MAX.

理论上,readv和writev可以通过在数组中多次重复相同的iov缓冲区来执行大于SIZE_MAX / 2的IO操作,但是如果我没记错的话,如果总大小将大于SSIZE_MAX,则指定它们失败。