【问题标题】:What is the correct definition of size_t? [duplicate]size_t 的正确定义是什么? [复制]
【发布时间】:2015-11-24 00:42:16
【问题描述】:

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

例如,“C Programming Language”第 2 版中的 K&R,在 2.2 数据类型和大小部分中,对整数做出了非常明确的陈述:

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

这是非常清楚和明确的。 size_t 类型并非如此。在 K&R 5.4 地址算术中,他们说:

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

C99 standard draft,在6.5.3.4 sizeof 运算符中,他们说:

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

7.17 通用定义中:

  • size_t是sizeof运算符结果的无符号整数类型;

7.18.3 其他整数类型的限制

  • size_t 的限制SIZE_MAX65535

还有一篇有用的文章——Why size_t matters。上面写着:

  • 好的,让我们试着想象一下,如果没有size_t 会怎样。
  • 例如,让我们从<string.h> 中获取void *memcpy(void *s1, void const *s2, size_t n); 标准函数
  • 让我们使用int 而不是size_t 作为n 参数。
  • 但是内存大小不能是负数,所以我们最好取unsigned int
  • 很好,看来我们现在很开心,没有size_t
  • 但是unsigned int 的大小有限 - 如果有一些机器可以复制大于unsigned int 可以容纳的内存块怎么办?
  • 好的,那我们就用unsigned long吧,现在我们开心了吗?
  • 但是对于那些使用较小内存块运行的机器,unsigned long 效率会很低,因为long 不是“自然的” 对他们来说,他们必须执行额外的操作才能使用 longs.
  • 所以我们为什么需要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,为什么要引入它,以及它真正代表什么。

【问题讨论】:

  • 至于你的第二点,65535是最低限度。所以size_t 至少是 16 位,但可能更多。
  • SIZE_MAX的常见定义请注意这里的common,即使它可能意味着common in 1990或所以。
  • 标准中的所有限制都是最低限制。这就是为什么 int 的限制是 32767 但实际上现在在大多数系统上 int 的限制是 2^31-1
  • 为什么不阅读标准,例如object.

标签: c c99 c11 size-t


【解决方案1】:

何时使用size_t

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

何时不使用size_t

当一个值可能为负时,例如当你减去指针时。这对于指向同一数组的指针是允许的,但它可能会产生负数,具体取决于指针的相对位置。为这种情况定义了另一种类型ptrdiff_t

为什么引入

标准的设计者可以选择引入单独的类型,或者要求现有类型能够容纳尺寸。第一个选择为编译器编写者提供了更大的灵活性,因此设计者使用了单独的类型。

它真正代表什么

它能够表示内存中对象的大小,可以是数组、structstructs 数组、structs 数组数组或其他任何东西。大小以字节表示。

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

【讨论】:

  • C 编译器和大量的 C 代码基础在 C89 标准之前就已经存在。一些现有代码依赖于“unsigned int”足够大以容纳最大可能对象的大小;其他现有代码依赖于具有特定大小的“unsigned int”,尽管它太小而无法表示非常大的对象的大小,但它还是很有用的。要求“sizeof”在所有实现中始终产生相同的预先存在的类型,这需要进行重大更改。
【解决方案2】:

C 中的“对象”是什么?

“对象”是一个定义的术语。 C99 标准将其定义为:“执行环境中的数据存储区域,其内容可以表示值”(第 3.14 节)。更通俗的定义可能是“在内存中存储一​​个值”。对象有不同的大小,具体取决于存储的值的类型。该类型不仅包括charint 等简单类型,还包括结构和数组等复杂类型。例如,数组的存储是一个object,其中每个元素都有一个object

为什么限制为 65535,这是可以用 16 位表示的最大数字? Embedded.com 上的文章说,size_t 也可以是 32 位。

你误会了。重新阅读第 7.18.3 节的前两段。 SIZE_MAX 表示size_t 类型的最大值,但其实际值取决于实现。标准中给出的值是可以达到的最小值值。在大多数实现中,它更大。

K&R 说,int 具有平台的“自然”大小,它可以等于 int 或 long。那么,如果它是“自然的”,为什么不使用它而不是 size_t 呢?

因为没有特别的理由将对象的最大大小限制为单个机器字中可表达的字节数(这几乎就是“自然大小”的意思)。同样,intlong 的大小不同,如果有的话,也不清楚哪一个应该对应于 size_t。使用size_t 而不是这些抽象机器细节之一,使您的代码更便携。

响应更新:

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

size_t 主要定义为sizeof 的结果类型。由此可见,它“真正代表”的是一个对象的大小。

使用size_t 保存表示对象大小或与对象大小相关的值。这就是它的用途。在大多数情况下,您可以通过类型匹配来完成此操作:使用size_t 类型的变量来存储声明为该类型的值,例如某些函数的返回值(例如strlen())和某些运算符的结果(例如sizeof)。

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

【讨论】:

  • ...没有什么特别的理由认为对象的最大大小应该限制在单个机器字中可表达的字节数... 那么为什么不呢?那么使用long
  • @Gill Bates 对象的最大大小应该限制在unsigned long long 并没有什么特别的原因。
  • @GillBates 因为也没有特别的理由让size_t 对应于long。正如我已经写过的,size_t 提供了一个抽象,因此您的代码不需要知道或依赖于您的特定实现的细节。
  • @JohnBollinger 取决于编译器开发人员决定对象应具有的最大大小?
  • @GillBates,是的。这就是“依赖于实现”的意思。该标准给出了符合编译器必须提供的最低要求,但编译器/库开发人员可以选择。通常,该选择由目标运行时环境的特征决定,但并非必须如此。
【解决方案3】:

为什么限制为 65535,这是可以用 16 位表示的最大数?

至少 16 位。

根据 1999 ISO C 标准 (C99),size_t 是至少 16 位的无符号整数类型(请参阅第 7.17 和 7.18.3 节)。

为什么要使用size_t

size_t 是保证保存任何数组索引的类型。

size_t 可以是unsigned charunsigned shortunsigned intunsigned longunsigned long long 中的任何一个(也可以是除这些之外的任何其他内容),具体取决于实现。

而使用unsigned intunsigned long 代替size_t,原因类似,它们不是唯一的无符号整数类型。

其目的是让程序员不必担心使用哪种预定义类型来表示尺寸。

在一个系统上,使用unsigned int 表示大小可能是有意义的;另一方面,使用unsigned longunsigned long long 可能更有意义。

因此使用size_t 增加了代码可能更便携的优势。

【讨论】:

    【解决方案4】:

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

    我想知道,什么时候用size_t,

    sizeof()malloc() 相关的所有内容。即对象的技术尺寸。

    何时不使用 size_t,

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

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

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

    【讨论】:

      猜你喜欢
      • 2023-01-28
      • 2014-08-04
      • 2015-07-10
      • 2011-06-21
      • 2019-07-06
      • 2014-08-12
      相关资源
      最近更新 更多