比较 size_t 和 -1

huangapple go评论58阅读模式
英文:

Comparing size_t to -1

问题

I'm staring at some library code (I am looking at you, Microchip), declared to return a size_t:

size_t SYS_FS_FileWrite(SYS_FS_HANDLE handle, const void *buf, size_t nbytes);

That is documented as returning -1 on an error. But size_t is an unsigned value. So, in theory and/or in practice, is the following allowed?

if (SYS_FS_FileWrite(handle, buf, nbytes) == -1) {
    report_errror();
}

这段代码中有一个问题,SYS_FS_FileWrite 返回的是 size_t 类型,但文档中说明在出错时返回 -1。然而,size_t 是无符号类型,不能直接与 -1 进行比较。这段代码在理论上和实际中都不允许。

英文:

Note: it has been suggested that this question duplicates https://stackoverflow.com/questions/3642010/comparing-int-with-size-t, but the question here specifically asks about comparing size_t with a negative value. For this reason, it should be re-opened. (And besides, it has generated a lot of thoughtful discussion!)

I'm staring at some library code (I am looking at you, Microchip), declared to return a size_t:

size_t SYS_FS_FileWrite(SYS_FS_HANDLE handle, const void *buf, size_t nbytes);

That is documented as returning -1 on an error. But size_t is an unsigned value. So, in theory and/or in practice, is the following allowed?

if (SYS_FS_FileWrite(handle, buf, nbytes) == -1) {
    report_errror();
}

答案1

得分: 16

以下是翻译的内容:

返回一个返回size_t的例程不可能返回-1,但如果相关环境不需要该值来进行冲突的用途,它完全可以返回将-1转换为size_t的结果。如果文档说明了后者,那就没问题。如果它说明了前者,那么文档写得很粗糙,可能意思是后者。

在对一些size_tx与-1进行比较时,例如x == -1,如果size_t的秩等于或超过int的秩,则值-1将被转换为size_t类型。这在大多数C实现中都是这样的,并且在将-1转换为size_t作为返回值的实现中也会预期到这种情况。在一个size_t的秩低于int的C实现中,x可能会被转换为int(取决于类型的一些特定情况)。这不会改变值,因此x == -1将始终评估为假。

根据评论中的一个请求,要测试SYS_FS_FileWrite(handle, buf, nbytes) == -1是否是对SYS_FS_FileWrite返回-1转换为size_t的安全测试,考虑到通常的算术转换可能不会产生所需的结果,一个合适的测试是_Static_assert((size_t) -1 == -1, "size_t类型太窄。");。此外,测试也可以写成SYS_FS_FileWrite(handle, buf, nbytes) == (size_t) -1

英文:

It is impossible for a routine that returns a size_t to return −1, but it is perfectly fine for it to return the result of converting −1 to size_t (presuming the relevant environment does not need that value for any conflicting purpose). If the documentation states the latter, it is fine. If it states the former, the documentation is sloppily written and probably means the latter.

In a comparison of some size_t value x to -1, as in x == -1, the value −1 will be converted to the type size_t if the rank of size_t equals or exceeds the rank of int. This is the case in most C implementations and would be expected in an implementation that uses −1 converted to size_t as a return value. In a C implementation in which size_t had lower rank than int, x could be converted to int (depending on some specifics of the types). That would not change the value, and x == -1 would always evaluate as false.

Per a request in the comments for a test of whether SYS_FS_FileWrite(handle, buf, nbytes) == -1 is a safe test for SYS_FS_FileWrite returning −1 converted to size_t in light of the fact that the usual arithmetic conversions might not produce the desired results, a suitable test is _Static_assert((size_t) -1 == -1, "size_t type is too narrow.");. Also, the test could be written as SYS_FS_FileWrite(handle, buf, nbytes) == (size_t) -1.

答案2

得分: 7

Yes, it is allowed and it will work as intended.

当比较整数常量-1(具有类型int)与类型为size_t的值时,整数常量-1将被隐式转换为size_t。假设size_t的宽度为64位,它将被转换为值0xFFFFFFFFFFFFFFFF。函数SYS_FS_FileWrite的返回值也将具有值0xFFFFFFFFFFFFFFFF。因此,比较将按预期工作。

正如其他回答中指出的,ISO C标准允许编译器实现定义数据类型size_t的方式,使其等级小于int。在这种假设的情况下,我前面段落中的陈述将不适用。整数常量-1将保留其值,不会转换为正值,因此比较将始终评估为假。然而,这只是一个理论上的关注点。在实际应用中,您可以依赖于size_t具有等于或高于int的等级。

文档中声明函数将返回-1并不太合理。文档更合理地应声明它将返回转换为size_t-1,即它将返回值(size_t)-1

英文:

Yes, it is allowed and it will work as intended.

When comparing the integer constant -1 (which has type int) with a value of type size_t, the integer constant -1 will be implicitly converted to size_t. Assuming that size_t has a width of 64 bits, it will be converted to the value 0xFFFFFFFFFFFFFFFF. The return value of the function SYS_FS_FileWrite will also have the value 0xFFFFFFFFFFFFFFFF. Therefore, the comparison will work as desired.

As pointed out in one of the other answers, the ISO C standard does allow a compiler implementation to define the data type size_t in such a way that its rank is smaller than int. In the hypothetical case of this actually happening, the statements in my previous paragraph would not apply. The integer constant -1 would retain its value and would not be converted to a positive value, so that the comparision would always evaluate to false. However, this is only a theoretical concern. In practice, you can rely on size_t having a rank that is equal to or higher than int.

It does not make much sense that the documentation states that the function will return -1. It would make more sense for the documentation to state that it will return -1 converted to a size_t, i.e. that it will return the value (size_t)-1.

答案3

得分: 1

在if语句的表达式中,

if (SYS_FS_FileWrite(handle, buf, nbytes) == -1) {

使用了两个不同类型的操作数。等式运算符的左操作数的类型是size_t,而右操作数是类型为int的整数常数-1

编译器需要确定这些操作数的公共类型。

在这种情况下,使用了所谓的通常算术转换。

由于类型size_t的等级不小于类型int的等级(类型size_t通常是类型unsigned long的别名,更少见的情况下是类型unsigned long long的别名),因此类型为int的操作数被转换为类型size_t

所以实际上,您在底层有:

if (SYS_FS_FileWrite(handle, buf, nbytes) == ( size_t )-1) {

就像从函数返回的整数常数-1根据函数返回类型转换为类型size_t一样:

size_t SYS_FS_FileWrite(SYS_FS_HANDLE handle, const void *buf, size_t nbytes)
{
    //...
    return ( size_t ) -1;
    //...
}

因此,如果函数返回-1,则if语句可以解释为:

if ( ( size_t )-1 == ( size_t )-1) {

前提是函数返回-1。否则,等式的左操作数具有函数返回的其他值,表达式将计算为逻辑假(整数值0)。

根据C标准(6.5.9相等运算符):

如果两个操作数都具有算术类型,则执行通常的算术转换。来自不同类型域的两个算术类型的任何两个值仅当它们转换为通常算术转换确定的(复杂的)结果类型的结果相等时才相等。

英文:

In the expression of the if statement

if (SYS_FS_FileWrite(handle, buf, nbytes) == -1) {

there are used two operands of different types. The left operand of the equality operator has the type size_t and the right operand is the integer constant -1 of the type int.

The compiler needs to determine the common type of the operands.

In this case there are used the so-called usual arithmetic conversions.

As the rank of the type size_t is not less than the rank of the type int (the typs size_t is usually an alias for the type unsigned long and in more rare cases for type unsigned long long) then the operand of the type int is converted to the type size_t.

So under the hood you have in fact

if (SYS_FS_FileWrite(handle, buf, nbytes) == ( size_t )-1) {

the same way as the returned integer constant -1 from the function is converted to the type size_t according to the function return type

size_t SYS_FS_FileWrite(SYS_FS_HANDLE handle, const void *buf, size_t nbytes)
{
    //...
    return ( size_t ) -1;
    //...
}

Thus the if statement may be interpreted like

if ( ( size_t )-1 == ( size_t )-1) {

provided that the function returns -1. Otherwise the left operand of the equation has some other value returned by the function and the expression evaluates to logical false (integer value 0)

From the C Standard (6.5.9 Equality operators)

> 4 If both of the operands have arithmetic type, the usual arithmetic
> conversions are performed.
Values of complex types are equal if and
> only if both their real parts are equal and also their imaginary parts
> are equal. Any two values of arithmetic types from different type
> domains are equal if and only if the results of their conversions to
> the (complex) result type determined by the usual arithmetic
> conversions are equal.

答案4

得分: 1

Sure, here are the translated parts:

> ...documented as returning -1

使用标准的 size_t,一个返回 size_t 的函数不可能返回 -1。这样的函数在使用 return -1; 时实际返回的是 (size_t) -1SIZE_MAX

> ... in theory and/or in practice, is the following allowed?

在某些实现中,如果 SIZE_MAX <= INT_MAX 为真,那么以下情况 永远 不成立,因为在比较之前 size_t 转换为 int,而所有的 size 都是非负的。

// 弱代码
size_t SYS_FS_FileWrite(SYS_FS_HANDLE handle, const void *buf, size_t nbytes);
if (SYS_FS_FileWrite(handle, buf, nbytes) == -1) {
  报告错误();
}

通常情况下 SIZE_MAX < INT_MAX 为假,所以 -1 会转换为 (size_t) -1SIZE_MAX,比较是正确的。

更好的写法是:

if (SYS_FS_FileWrite(handle, buf, nbytes) == SIZE_MAX) {
  报告错误();
}

在审查中,这个答案与其他答案过于相似,因此可能会被合并到维基中。

英文:

> ...documented as returning -1

With standard size_t, impossible for a function returning size_t to return -1. Such a function with return -1; instead returns (size_t) -1 or SIZE_MAX.

> ... in theory and/or in practice, is the following allowed?

On select implementations where SIZE_MAX <= INT_MAX is true, the following is never true, since size_t converts to an int before the compassion and all size are non-negative.

// Weak code
size_t SYS_FS_FileWrite(SYS_FS_HANDLE handle, const void *buf, size_t nbytes);
if (SYS_FS_FileWrite(handle, buf, nbytes) == -1) {
  report_errror();
}

Commonly SIZE_MAX < INT_MAX is false though, so the -1 converts to a (size_t) -1 or SIZE_MAX and the compare is OK.

Better as:

if (SYS_FS_FileWrite(handle, buf, nbytes) == SIZE_MAX) {
  report_errror();
}

On review, this answer too close to other answers, so many it wiki.

huangapple
  • 本文由 发表于 2023年4月17日 21:06:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76035482.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定