size_t
被声明为unsigned int
,因此它不能代表负值。
因此ssize_t
是已签名的类型size_t
对吗?
这是我的问题:
#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;
}
为什么我得到了:
18446744073709551591
18446744073709551586
结果?
我知道用size_t
这是可能的,因为它是一个无符号类型,但为什么我的错误结果也是ssize_t
??
答案 0 :(得分:19)
在第一种情况下,您指定的是无符号类型 - a
。在第二种情况下,您使用了错误的格式说明符。第二个说明符应为%zd
而不是%zu
。
答案 1 :(得分:1)
首先,您应该检查两种类型的实际大小。 类似下面的代码片段应该做的事情:
#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;
}
在两种情况下,我得到(64位Linux,GCC v7.2)“8字节”,这与long int和long long int相同,是最大的CPU本机整数值。
当尺寸相同时(并且它们应该始终如此),size_t
可以具有比ssize_t
“绝对值大2倍的”,而ssize_t
反过来可以签名(正面或负面) )值。
如果它们不同,那么较大的那个会更大......因此可以适应更大的值。
但最后,size_t
和size_t
是用于“谈论”大小,长度,内存量等的两种不同类型。
前者只是放弃了1位的值,以获得发出某种错误所需的符号。
最后,这两种类型不可互换,至少并非总是如此。
当大小超过2 ^ 63字节/项时,差异很明显。
ssize_t
会strlen()
不会溢出。
在“正常”情况下,您可以从一个投射到另一个。 对于我之前提到的案例,你永远不应该混淆它们。
作为参考,malloc()
和size_t
都使用read()
,而readv()
和ssize_t
都使用ssize_t。
因此,size_t
不是 unsigned long
的签名版本,因为它们具有非重叠的领域。
然后,对于您的问题,您看到的两个数字相差5个单位,这正是您所期望的。您看到的是signed long
时这两个变量的值。请尝试将其打印为%ld
(.
└── dira
├── a
├── b
├── c
└── dirb
)。
答案 2 :(得分:0)
...为什么我也用
ssize_t
得到了错误的结果??
使用
ssize_t b = -30;
printf("%jd\n", (intmax_t) b);
使用匹配的说明符,对于否定的ssize_t
,不是 %zu
。
ssize_t b = -30;
printf("%zu\n", b); // problem.
ssize_t
没有C指定的打印说明符。 C甚至没有指定ssize_t
。
对C的各种扩展确实指定了ssize_t
,在Linux中,也指定了打印说明符。
Linux Programmer's Manual确实具有:
z:以下整数转换对应于
size_t
或ssize_t
参数“,
printf("%zd\n", b); // OK for that Linux
size_t
旨在作为size_t
的带符号类似物。措辞是这样的,实现可以选择使用更长的类型,也可以简单地使用位于size_t
之下的类型的带符号版本。
由于ssize_t
可能(通常)比size_t
宽,因此使用"%zd"
可以调用未定义的行为(UB)。将C99转换为C intmax_t
之后最宽的标准有符号类型并进行打印非常简单。
printf("%jd\n", (intmax_t) b); // OK for general use
答案 3 :(得分:-4)
溢出coz size_t是UNSIGNED 当您尝试将size_t设置为(-val)时 你得到溢出并获得SIZE_T_MAX - val
例如: size_t val = -20; // val == 18446744073709551615 - 20;