在C++和/或C中,size_t和int有什么区别?

41
为什么在C++容器中使用size_type而不是int?如果我们创建自己的结构,是否应该使用size_type
回答:使用size_type可以确保代码在不同平台上具有可移植性,并且可以处理大型容器。因此,建议在自定义数据结构时也使用size_type

在https://dev59.com/IHNA5IYBdhLWcg3wjOlS上有一个size_t和size_type的比较。 - nik
@PCBEEF,你第一次就做对了,basic_string::size返回的是size_type而不是size_t。请参见http://msdn.microsoft.com/en-us/library/s50w4ze4.aspx。 - Eugene Yokota
9个回答

33
一般情况下,无论何时计算某物的大小,都应该使用size_t。很奇怪的是,size_t只需要表示0到SIZE_MAX字节之间的值,而SIZE_MAX只需要为65,535,这个限制非常有趣,源自C++和C标准的其他约束如下:
  • sizeof()的返回类型是size_t,并且它是无符号整数
  • operator new()size_t参数形式接收要分配的字节数
  • size_t<cstddef>中被定义
  • SIZE_MAX在C99中在<limits.h>中被定义,但在C++98中没有提到?!
  • size_t未包括在“基本整数类型”列表中,因此我一直认为size_t是用于基本类型之一的类型别名:charshort intintlong int
如果您正在计算字节数,则绝对应该使用size_t。如果您正在计算元素数量,则可能应该使用size_t,因为这似乎是C++一直在使用的。无论如何,您都不应该使用int——如果必须使用,则至少使用unsigned longunsigned long long(如果使用TR1)。更好的做法是将您最终使用的任何类型定义为size_type,或只需包含<cstddef>并使用std::size_t

14
size_t不仅需要支持到64k,还需要能够表示任意对象的大小(我认为这是C标准要求,所以可能C++标准没有提到)。几乎所有编译器都必须将其大小设置为指针大小。这并不像看起来那么奇怪。 - Steve Jessop
是的,在内存中表示任何单个对象分配的大小是必需的。不需要表示最大对象数,只需要表示最大可表示对象所占用的字节数。将size_t的范围与可寻址内存进行比较并不是一个有效的比较,除非您可以在单个对象中分配整个可寻址内存范围。 - D.Shawley
1
因此,“几乎任何编译器”都可以。现在,我们大多数都有未分段的内存架构,并且希望映射大型文件,大多数编译器实现了intptr_t(来自C99)或类似类型,因此人为地将对象的大小限制为比可以跨越地址空间的较小整数类型更小的类型没有太多优势。这就是为什么我认为C++实现使用size_t作为size_type并不奇怪的原因。 64k SIZE_MAX最小值如此之低可能只是为了支持16位体系结构:您不会期望32位+编译器实际执行该操作。 - Steve Jessop

10

以下是可能的几个原因:

  • size_t类型可以在该平台上定义为最大的无符号整数。例如,它可能被定义为32位整数或64位整数,或者完全不同的东西,能够存储长度很长的无符号值。
  • 在阅读程序时,使其显然是一个大小而不仅仅是“常规” int 的值。

如果您只是编写一个只供自己和/或丢弃的应用程序,则可以使用基本的int。如果您正在编写库或类似的重要代码,那么size_t可能是更好的选择。


2
想象一下一个简单的刚启动的64位操作系统,没有任何多余的软件,你可以使用new char[6 gigs],只要你有足够的RAM或交换空间,它就能正常工作。现在,如果你用int类型来管理它,该怎么办呢?这就是size_t背后的原因。 - v.oddou

8

有些答案比必要的复杂。size_t是一种无符号整数类型,保证足够大以存储内存中任何对象的字节大小。实际上,它的大小总是与指针类型相同。在32位系统上,它为32位。在64位系统上,它为64位。


1
开个玩笑:我想起了一个可能反驳同样大小指针/size_t的例子。在DOS 16位段:16位偏移方案中,指针是32位的,而size_t则被限制为16位。希望这样的方案不会再次出现。 - chux - Reinstate Monica
1
这实际上是正确的。在C语言中,段/偏移量确实不是一个指针,因为你不能自然地对它进行算术运算(尽管编译器在“巨大”模式下生成的代码可以很好地隐藏这一点)。通过偏移量可以寻址的最大单个内容确实是65536字节。 - Andy Ross

2

STL中的所有容器都有各种typedefs。例如,value_type是元素类型,size_type是存储数字类型。这样,容器完全基于平台和实现而成为通用的。

如果您正在创建自己的容器,也应该使用size_type。通常会这样做。

typedef std::size_t size_type;

如果您想要获取容器的大小,您应该编写以下代码:
typedef vector<int> ints;
ints v;
v.push_back(4);
ints::size_type s = v.size();

很好的一点是,如果以后你想使用列表,只需更改typedef即可。
typedef list<int> ints;

它仍然可以正常工作!


1

我猜你指的是 "size_t" -- 这是一种表示无符号整数(只能为正数,永远不会为负数)的方式 -- 对于容器的大小来说很有意义,因为你不能有一个大小为 -7 的数组。我不会说你必须使用 size_t,但它确实向使用你的代码的其他人表明“这里的数字总是正数”。它还给你更大范围的正数,但那可能不重要,除非你有一些非常大的容器。


1
size_t和size_type(尽管它们通常具有相同的值)是两个不同的概念。 - Eugene Yokota

1

C++是一种可以在不同硬件架构和平台上实现的语言。随着时间的推移,它已经支持了16位、32位和64位架构,未来可能还会支持其他架构。 size_type 和其他类型别名是库为了使程序员/代码与实现细节隔离开来的方式。

假设size_type在32位机器上使用32位,在64位机器上使用64位,则相同的源代码如果你在需要的地方使用了size_type,很可能会更好地工作。在大多数情况下,您可以假设它与unsigned int相同,但不能保证。

size_type用于表示STL容器(如std::vector)的容量,而size_t用于表示C/C++中对象的字节大小。


0

在规范中,整数的大小不能保证为4个字节,因此它们不可靠。是的,size_type优于ints。


size_t的大小是否保证是特定的? - Tyler
3
有趣的是,它们只需要能够表示0到65,535之间的值。标准中相关的条款是C99的7.18.3。实际的限制是在0和<limits.h>中定义的SIZE_MAX之间。 - D.Shawley
@DShawley int 只能保证能够表示最多 32,767。所以我不确定你的观点是什么。 - M.M

0

size_t是无符号的,因此即使它们都是32位,它也不像未经限定的int那样意味着完全相同的事情。我不确定为什么他们添加了这个类型,但在今天的许多平台上,sizeof(size_t)==sizeof(int)==sizeof(long),所以你选择哪种类型取决于你自己。请注意,这些关系不被标准保证,并且随着64位平台的发展,它们正在迅速过时。

对于您自己的代码,如果您需要表示某个概念上的“大小”并且永远不可能为负数,那么size_t将是一个很好的选择。


-5
void f1(size_t n) {
    if (n <= myVector.size()) { assert(false); }
    size_t n1 = n - myVector.size(); // bug! myVector.size() can be > n       
    do_stuff_n_times(n1);
}

void f2(int n) {
    int n1 = n - static_cast<int>(myVector.size());
    assert(n1 >= 0);
    do_stuff_n_times(n1);
}

f1()和f2()都有同样的bug,但在f2()中检测问题更容易。对于更复杂的代码,无符号整数算术错误不容易识别。

个人而言,除非需要使用无符号整数,否则我会为所有大小使用有符号整数。我从未遇到过我的大小无法适应32位有符号整数的情况。在使用32位无符号整数之前,我可能会使用64位有符号整数。

使用有符号整数作为大小的问题是你的代码中有很多从size_tintstatic_cast


这其实不是一个很好的点,因为 assert(n >= myVector.size()); 可以完美地检测到错误。 - stefan

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