简体   繁体   English

C size_t 和 ssize_t 负值

[英]C size_t and ssize_t negative value

size_t is declared as unsigned int so it can't represent negative value. size_t被声明为unsigned int因此它不能表示负值。
So there is ssize_t which is the signed type of size_t right?所以有ssize_tsize_t的有符号类型,对吗?
Here's my problem:这是我的问题:

#include <stdio.h>
#include <sys/types.h>

int main(){
size_t a = -25;
ssize_t b = -30;
printf("%zu\n%zu\n", a, b);
return 0;
}

why i got:为什么我得到:

18446744073709551591
18446744073709551586

as result?结果?
I know that with size_t this could be possible because it is an unsigned type but why i got a wrong result also with ssize_t ??我知道使用size_t这可能是可能的,因为它是一个无符号类型,但是为什么我用ssize_t也得到了错误的结果??

In the first case you're assigning to an unsigned type - a .在第一种情况下,您分配给无符号类型 - a In the second case you're using the wrong format specifier.在第二种情况下,您使用了错误的格式说明符。 The second specifier should be %zd instead of %zu .第二个说明符应该是%zd而不是%zu

First of all you should check the actual size of the two types.首先,您应该检查两种类型的实际大小。 Something like the following snippet should do:像下面的代码片段应该做的事情:

#include <stdio.h>
#include <unistd.h>

int main() {
  printf( "sizeof(  size_t ) = %d bytes\n",(int) sizeof( size_t) );
  printf( "sizeof( ssize_t ) = %d bytes\n",(int) sizeof( ssize_t) );
  return 0;
}

I get (64bit Linux, GCC v7.2) "8 bytes" in both cases, which is the same as long int and long long int, the maximum CPU-native integer value.我在这两种情况下都得到(64 位 Linux,GCC v7.2)“8 字节”,这与 long int 和 long long int 相同,即最大 CPU 原生整数值。

When the sizes are the same (and they should always be), size_t can have "2x larger absolute values" than ssize_t which, in turn, can have signed (that's either positive or negative) values.当大小相同(并且它们应该始终相同)时, size_t绝对值可以比ssize_t “大 2 ssize_t ”,而ssize_t又可以有符号(正或负)值。

If they were different, then the larger one would be ... larger and could thus accommodate for larger values.如果它们不同,那么较大的将......更大,因此可以容纳更大的值。

But in the end, ssize_t and size_t are two different types used to "talk" about sizes, lengths, amounts of memory and so on.但最终, ssize_tsize_t是两种不同的类型,用于“谈论”大小、长度、内存量等。

The former is just ditching 1 bit for the value in order to gain the sign needed to signal some sort of error.前者只是为该值丢弃 1 位,以获得发出某种错误信号所需的符号。

Finally, the two types are not interchangeable, not always at least.最后,这两种类型不可互换,至少并非总是如此。 When the size can go past 2^63 bytes/items the difference is clear.当大小可以超过 2^63 字节/项目时,差异就很明显了。 size_t won't overflow while ssize_t will. size_t不会溢出而ssize_t会。

Under "normal" circumstances you can cast from one to the other one.在“正常”情况下,您可以从一个转换到另一个。 For the cases I mentioned earlier, you should never mix them.对于我之前提到的情况,您永远不应该混合使用它们。

Just as a reference, both strlen() and malloc() use size_t , while both read() and readv() use ssize_t.作为参考, strlen()malloc()使用size_t ,而read()和 readv readv()使用 ssize_t 。

So, ssize_t is not the signed version of size_t as there are values in ssize_t that cannot be mapped on a size_t (like -1 ) and viceversa.因此, ssize_t不是size_t的签名版本,因为ssize_t中的某些值无法映射到size_t (如-1 ),反之亦然。 And library functions either use one type or the other one.库函数要么使用一种类型,要么使用另一种。

Then, to your questions, the two numbers you see differ by 5 units, that's exactly what you'd expect.然后,对于您的问题,您看到的两个数字相差 5 个单位,这正是您所期望的。 What you see is the value of those two variables when seen as unsigned long .您看到的是这两个变量在被视为unsigned long时的值。 Try printing them as signed long ( %ld ) instead so you can still see the sign.尝试将它们打印为有signed long ( %ld ),这样您仍然可以看到符号。

... why i got a wrong result also with ssize_t ?? ...为什么我的ssize_t也得到了错误的结果??

Use采用

ssize_t b = -30;
printf("%jd\n", (intmax_t) b); 

Use a matching specifier, which for a negative ssize_t is not %zu nor certainly "%zd" .使用匹配的说明符,对于负ssize_t不是%zu也不是"%zd"
How to use “zd” specifier with printf() ?如何在printf()使用“zd”说明符? . .

ssize_t b = -30;
printf("%zu\n", b);  // problem.

ssize_t does not have a C specified print specifier. ssize_t没有 C 指定的打印说明符。 C does not even specify ssize_t . C 甚至没有指定ssize_t

Various extensions to C do specify ssize_t and in a case of Linux, the print specifier also. C 的各种扩展确实指定了ssize_t ,在 Linux 的情况下,也指定了打印说明符。 Linux Programmer's Manual does have: Linux Programmer's Manual确实有:

z: A following integer conversion corresponds to a size_t or ssize_t argument", z: 以下整数转换对应于size_tssize_t参数",

printf("%zd\n", b);  // OK for that Linux

POSIX B.2.12 Data Types has POSIX B.2.12 数据类型

ssize_t This is intended to be a signed analog of size_t . ssize_t这旨在成为size_t有符号模拟。 The wording is such that an implementation may either choose to use a longer type or simply to use the signed version of the type that underlies size_t .措辞是这样的,实现可以选择使用更长的类型或简单地使用作为size_t基础的类型的签名版本。


Since ssize_t may (uncommonly) be wider than size_t , using "%zd" could invoke undefined behavior (UB).由于ssize_t可能(不常见)比size_t宽,因此使用"%zd"可能会调用未定义的行为(UB)。 It is simple enough to cast to the widest standard signed type since C99 as intmax_t and print.将 C99 以来最宽的标准有符号类型转换为intmax_t并打印非常简单。

printf("%jd\n", (intmax_t) b);  // OK for general use

Overflow coz size_t is a UNSIGNED when you try to set size_t as (-val) you get overflow and get SIZE_T_MAX - val溢出因为 size_t 是 UNSIGNED,当您尝试将 size_t 设置为 (-val) 时,您会溢出并获得 SIZE_T_MAX - val

for example: size_t val = -20;例如:size_t val = -20; //val == 18446744073709551615 - 20; //val == 18446744073709551615 - 20;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM