size_t的正确定义是什么?

5

首先,我所说的“正确定义”是什么意思?

例如,在K&R的《C程序设计语言》第二版中,第2.2节“数据类型和大小”中,他们对整数类型作出了非常明确的陈述:

  • shortintlong三种整数类型。它们需要表示不同边界的值。
  • int是特定硬件的“自然”大小数字,因此可能是最快的。
  • 整数类型shortintlong的大小完全取决于实现。
  • 但它们有限制。
  • shortint至少应该容纳16位。
  • long至少应该容纳32位。
  • short >= int >= long

这非常明确和明显。但对于 size_t 类型并非如此。在 K&R 5.4 地址算术中,他们说:

  • ...size_t 是由 sizeof 运算符返回的无符号整数类型。
  • sizeof 运算符产生其操作数类型的对象所需的字节数。

C99标准草案 中,在6.5.3.4 sizeof运算符中,他们说:

  • 结果的值是实现定义的,其类型(无符号整数类型)为 size_t,定义在 <stddef.h>(和其他标题)中。

7.17 公共定义中:

  • size_t 是 sizeof 运算符的无符号整数类型的结果;
7.18.3 其他整数类型的限制中:
  • size_t的极限值是SIZE_MAX,为65535
还有一篇有用的文章 - 为什么size_t很重要。它说:
  • 好的,让我们试着想象一下,如果没有size_t会怎样。
  • 例如,让我们从<string.h>标准库中取出void *memcpy(void *s1, void const *s2, size_t n);函数。
  • 我们用int代替n参数中的size_t
  • 但是内存的大小不能为负数,所以最好使用unsigned int
  • 很好,看起来我们现在很满意,没有了size_t也可以。
  • 但是unsigned int有限制的大小——如果有些机器可以复制大于unsigned int所能容纳的内存块怎么办?
  • 好吧,那么我们就使用unsigned long,现在我们满意了吗?
  • 但是对于那些操作更小内存块的机器而言,unsigned long将会效率低下,因为对于它们来说,long不是“自然”的类型,必须执行额外的操作才能使用long
  • 所以这就是为什么我们需要size_t——用来表示特定硬件一次能够操作的内存大小。在某些机器上,它将等于int,在其他机器上则等于long,具体取决于它们使用哪种类型最有效。
我理解的是,size_t 严格绑定了 sizeof 运算符。因此,size_t 表示对象的最大字节数。它也可能表示特定 CPU 型号一次可以移动的字节数。

但是,这里仍然有很多谜团:

  • C 语言中,“对象”是什么意思?
  • 为什么它被限制为 65535,这是可以由 16 位表示的最大数字?embedded.com 上的文章说,size_t 也可以是 32 位。
  • K&R 说,int 对于平台来说具有“自然”的大小,它可以等于 intlong。那么如果它是“自然的”,为什么不使用它而不是 size_t

更新

有类似的问题:

What is size_t in C?

但是它的答案没有提供清晰的定义或权威来源链接(如果不计算维基百科)。

我想知道何时使用size_t,何时不使用size_t,为什么引入它,以及它真正代表什么。


6
size_t在C语言中是一种用来表示对象大小的无符号整数类型。它通常被用作内存分配函数(如malloc)中参数和返回值的类型,以及数组索引的类型。具体大小取决于编译器和系统架构。 - Martin G
4
关于你的第二个观点,65535是最小限制。因此,size_t至少为16位,但可能更多。 - Kninnug
SIZE_MAX的常见定义。请注意,“常见”在这里可能意味着大约在1990年左右比较普遍的定义。 - dhke
标准中的所有限制都是最小限制。这就是为什么int的限制是32767,但实际上现在大多数系统上int的限制是2^31-1。 - phuclv
为什么不阅读标准,例如object - too honest for this site
4个回答

3
在C语言中,“对象”是一个定义过的术语。C99标准将其定义为“执行环境中的数据存储区域,其内容可以表示值”(第3.14节)。更通俗易懂的定义可能是“用于存储值的内存存储”。对象的大小因所存储的值的类型而异。该类型不仅包括简单类型,例如char和int,还包括复杂类型,例如结构体和数组。例如,数组的存储区域是一个“对象”,其中每个元素都有一个“对象”。
您误解了问题。请重新阅读第7.18.3节的前两段。SIZE_MAX 表示 type size_t 的最大值,但它的实际值取决于具体实现,标准给出的值只是可以达到的最小值。在大多数实现中,SIZE_MAX 的值都比这个更大。
因为没有特定的原因将对象的最大大小限制为可在单个机器字中表示的字节数(这几乎是“自然大小”意味着的),并且在int和long的大小不同的情况下,不清楚哪一个应该对应于size_t,如果有的话。使用size_t抽象掉了机器细节,使代码更具可移植性。
size_t主要被定义为sizeof的结果类型,因此它所“真正代表”的是对象的大小。使用size_t来存储与对象大小相关的值。这正是它的用途。在大多数情况下,您可以通过类型匹配来实现此目的:使用size_t类型的变量来存储声明具有该类型的值,例如某些函数的返回值(例如strlen())和某些运算符的结果(例如sizeof)。

不要将size_t用于表示除对象大小或与对象大小密切相关的其他值(例如对象大小的总和或正差)。


“一个对象的最大大小应该被限制在单个机器字节可表示的字节数之内”并没有特别的原因,那为什么不使用long呢? - Gill Bates
@Gill Bates 没有特定的原因限制对象的最大大小,甚至可以超过 unsigned long long - chux - Reinstate Monica
2
@GillBates,是的。这就是“实现相关”的意思。标准规定了符合要求的编译器必须提供的最低限度,但编译器/库开发人员可以自行选择。通常,这种选择受目标运行时环境的特性所支配,但并非必须如此。 - John Bollinger
size_t 可以比 unsigned long long 更大吗? - Gill Bates
标准没有规定 size_t 相对于其他整数类型的大小。因此,原则上它可能比 unsigned long long 更大。但实际上,我不知道有任何实现会比它更大。 - John Bollinger
显示剩余2条评论

3

何时使用size_t

使用size_t表示非负索引,并处理可以追溯到sizeof表达式的值。

何时不使用size_t

当值可能为负数时,例如减去指针时,不要使用size_t。这对于指向同一数组的指针是允许的,但根据指针的相对位置可能会产生负数。在这种情况下定义了另一种类型ptrdiff_t

它被引入的原因

标准的设计者可以选择引入一个单独的类型或要求现有类型能够保存大小。第一种选择给编译器编写者更多的灵活性,因此设计者选择了一个单独的类型。

它真正代表什么

它能够表示内存中对象的大小,无论是数组、结构体、结构体数组、结构体数组的数组还是其他任何东西。大小以字节为单位表示。

该类型也方便用于非负索引的使用,因为它可以表示到最大粒度的任何大小的结构的索引(即最大可能的char数组的索引,因为标准要求char具有最小可能的大小1)。


C89标准出现之前,C编译器和大量的C代码已经存在。一些现有的代码依赖于“unsigned int”足够大以容纳最大可能的对象的大小;其他现有的代码则依赖于“unsigned int”具有特定的大小,尽管它太小而无法表示非常大的对象的大小。要求“sizeof”在所有实现中始终产生相同的预先存在的类型将需要进行破坏性更改。 - supercat

2
为什么要将其限制在65535以内?这是16位能够表示的最大数字。
至少需要16位。
根据1999年ISO C标准(C99),size_t是一个无符号整数类型,至少为16位(请参见7.17和7.18.3节)。
为什么要使用size_t?
size_t是一种保证能够容纳任何数组索引的类型。
size_t可以是以下任意一种类型(也可以是其他类型),包括unsigned char、unsigned short、unsigned int、unsigned long或unsigned long long,具体取决于实现方式。
使用unsigned int或unsigned long代替size_t的原因类似,因为它们不是唯一的无符号整数类型。
它的目的是让程序员不必担心预定义类型中使用哪个来表示大小。
在某个系统上,使用unsigned int来表示大小可能是有意义的;在另一个系统上,使用unsigned long或unsigned long long可能更有意义。
因此,使用size_t的优点在于代码更容易移植。

1

没有(唯一的)“正确定义”。如前所述,它是由实现定义的。

我想知道何时使用size_t,

sizeof()malloc()有关的所有内容。也就是说,对象的技术尺寸。

何时不使用size_t,

用于正常(面向领域)计数和数字。

为什么引入它以及它真正代表什么。

它提供了一种处理大小和分配的实现无关方式,即它允许您编写可移植的代码。


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