C size_t和ssize_t负值

size_t声明为unsigned int因此它不能表示负值。
那么ssize_tsize_t签名类型吗?
这是我的问题:

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

为什么我得到:

 18446744073709551591 18446744073709551586 

结果?
我知道使用size_t这可能是因为它是一个无符号类型,但为什么我的ssize_t也得到了错误的结果?

在第一种情况下,您将分配给无符号类型 – a 。 在第二种情况下,您使用了错误的格式说明符。 第二个说明符应为%zd而不是%zu

首先,您应该检查两种类型的实际大小。 像下面的代码片段应该做的事情:

 #include  #include  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; } 

在两种情况下,我得到(64位Linux,GCC v7.2)“8字节”,这与long int和long long int(最大CPU本机整数值)相同。

当大小相同(并且它们应该始终是)时,size_t可以具有比ssize_t大2倍的绝对值,而ssize_t又可以具有签名(即正或负)值。

如果它们不同,则较大的那个会更大,因此可以容纳更大的值。

但最后,ssize_t和size_t是用于“谈论”大小,长度,内存量等的两种不同类型。

前者只是放弃了1位的值,以获得发出某种错误信号所需的符号。

最后,这两种类型不可互换,至少并非总是如此。 当大小超过2 ^ 63字节/项时,差异很明显。 size_t不会溢出而ssize_t会溢出。

在“正常”情况下,您可以从一个投射到另一个。 对于我之前提到的案例,你永远不应该混淆它们。

作为参考,strlen()和malloc()都使用size_t,而read()和readv()都使用ssize_t。

因此,ssize_t不是size_t的签名版本,因为它们具有非重叠的域。

那么,对于你的问题,你看到的两个数字相差5个单位,这是你所期望的。 你看到的是当被视为“无符号长”时两个变量的值。 尝试将它们打印为“签名长”(%ld)。

溢出时coz size_t是UNSIGNED,当你尝试将size_t设置为(-val)时,你会溢出并获得SIZE_T_MAX – val

例如:size_t val = -20; // val == 18446744073709551615 – 20;