我应该使用size_t还是ssize_t?

118
在我的代码中,我不使用 int 或 unsigned int。我只使用 size_t 或 ssize_t 来保持可移植性。例如:
typedef size_t intc;    // (instead of unsigned int)
typedef ssize_t uintc;  // (instead of int)

因为 strlenstringvector 等都使用 size_t,所以我通常使用 size_t。只有在可能为负数时才使用 ssize_t

但是我发现:

无符号整数类型非常适合将存储视为位数组的用途。使用无符号整数代替 int 来获得一个额外的比特位来表示正整数几乎从来不是一个好主意。通过声明变量为无符号来确保某些值为正数的尝试通常会被隐式转换规则所打败。

这是在书籍 The C++ Programming Language 中提到的。

所以我感到困惑。我错了吗?为什么 STL 没有遵守这本书上的建议呢?


1
size_t 用于表示大小的标准库。如果容器的大小是负数,那将是奇怪的。接口规定了它的行为。我认为这本书假设了日常使用,而不是接口。 - kassak
2
@kassak - 不,实际上在这种情况下使用了无符号类型来获取一个额外的位数。委员会的一些成员认为能够拥有比可用内存的一半更大的std::vector<char>非常重要。而且引用中说“几乎从不”... - Bo Persson
5
提名重新开放,因为所引用的重复帖子未能充分涵盖此贴的关闭原因。 - chux - Reinstate Monica
4
在注释中使用“[有符号] int”来表示无符号的size_t,并且使用unsigned int来表示有符号的ssize_t,并将其命名为intcuintc,这让我感到困惑,因为通常“u”代表无符号,例如uint32_tint32_t的无符号版本,是一个4字节的整数。因此建议使用更具描述性的名称来避免混淆。 - RastaJedi
5
对于那些被标记为重复的人。这绝对不是一个重复的问题。这个问题不是关于 signed 和 unsigned 的,而是关于 size_t 和 ssize_t 的,也就是说,“我应该在什么情况下使用它们”? - EnzoR
显示剩余3条评论
2个回答

188
ssize_t 用于那些返回值可能是有效大小,或者负值以表示错误的函数。它保证至少能存储在范围内的值 [-1, SSIZE_MAX]SSIZE_MAX取决于系统)。
因此,当你想要返回以字节为单位的大小时,请使用 size_t,而当你需要返回以字节为单位的大小或(负数)错误值时,请使用 ssize_t
参见:http://pubs.opengroup.org/onlinepubs/007908775/xsh/systypes.h.html

41
这个答案没有充分解释基于纯接口考虑做出这样决定的后果。任何实现不太可能为 ssize_t 使用比 size_t 更宽的类型。这意味着你为了能够返回负值而付出的代价是该类型正数范围的一半。也就是说,SSIZE_MAX 通常是 SIZE_MAX / 2。应该牢记这点。在很多情况下,仅仅为了能够返回 -1 负值是不值得付出这个代价的。 - AnT stands with Russia
12
@AnT认为C++中使用未签名类型是其中最大的失误之一。这种代价值得付出,没有任何情况不需要。如果你需要处理如此大的数字,请使用int64_t代替... - thesaint
11
@thesaint 你到底在说什么?这不是关于容量的问题。如果栈指针的当前值可能是负数或正数,你怎么能将四添加到栈指针上呢? - josaphatv
12
无符号整数是不是先于有符号整数出现,是因为硬件的原因——显然这更接近裸金属 C,而不是大多数 C++ 用法,但使用 MSB 允许有符号算术并不仅仅是为了减少“整数”可以表示的绝对值范围一半,而是因为需要进行减法运算。有符号整数和无符号整数就像梨和苹果——它们不同,但在某些有限的情况下可以相互转换...!(它们各自的一半范围是重叠的。) - SlySven
3
在我看来,混淆似乎出现在一个应该只产生无符号值的函数上,例如read(2)实际读取的字节数。然而,在发生错误的情况下,返回-1的值(可能编码为所有位都设置) - 这并不是为了让事情变得困难,而是因为它是一个哨兵值,正常情况下不会出现。 - SlySven
显示剩余13条评论

39

ssize_t不在标准库中,也不具备可移植性。处理对象大小时应使用size_t(还有用于指针差异的ptrdiff_t)。


28
ssize_t源自POSIX:http://pubs.opengroup.org/onlinepubs/009696799/basedefs/sys/types.h.html - Kafumanto
1
C++11及以后版本实现了模板std::make_signed,但如果使用size_t作为其参数是否定义良好则有些灰色地带。在C++20中,使用此模板与标准不允许的类型会导致代码不良形成,但现有的实现允许使用size_t - Swift - Friday Pie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接