【问题标题】:Why size_t when int would suffice for the size of an array?为什么 size_t 当 int 足以满足数组的大小时?
【发布时间】:2011-08-25 15:42:04
【问题描述】:

C 标准保证int 能够存储所有可能的数组大小。至少,这就是我通过阅读第 6.5.2.1 节第 1 小节(数组下标约束)所理解的:

其中一个表达式的类型应为“指向对象类型的指针”,另一个表达式应为 具有整数类型,结果具有“类型”类型。

既然我们要用ints 作为数组下标,为什么要使用size_t 来确定数组的大小呢?

int 足够时,为什么strlen() 返回size_t

【问题讨论】:

  • size_t 通常是无符号的。由于 -1 的字符串大小似乎有些无意义,那我为什么要支持它呢?
  • 通常不会。它必须是无符号类型。一些错误的实现曾经签署了size_t,这导致了极其严重的可利用漏洞。
  • 还有mallocsize_t 作为参数。知道使用什么作为数组下标并非易事:stackoverflow.com/questions/3174850/type-for-array-index-in-c99

标签: c int standards size-t


【解决方案1】:

术语“整数类型”并不意味着 int - 例如,charshort 是整数类型。

仅仅因为您可以使用int 为数组下标并不一定意味着它可以到达所有可能的数组元素。

更具体地说,关于 size_tint,一个示例是平台,其中int 可能是 16 位类型,size_t 可能是 32 位类型(或更常见的 32 位int 与 64 位 size_t 在当今 64 位平台上的区别)。

【讨论】:

    【解决方案2】:

    整数类型不一定是“int”。 “long long”也是整数类型,“size_t”也是。

    数组可以大于 2GB。对于那些编写需要大量内存的程序的人来说,此属性非常方便,例如具有大缓冲池的 DBMS、具有大内存缓存的应用程序服务器等。大于 2GB/4GB 的数组是 64 位计算的重点:)

    strlen() 的 size_t,至少听起来与 C 标准处理数组的方式兼容,无论它是否具有实际意义,或者是否有人见过这么大的字符串,都是另一个问题。

    【讨论】:

    • 虽然它们原则上可以存在,但最好让程序禁止大小大于 INT_MAX 的字符串,因为 snprintf 返回 int 并在结果字符串较长时给出溢出错误(即,如果您希望允许长度超过 2GB 的字符串,那么处理字符串的最佳安全方法将变得不可用)。
    【解决方案3】:

    首先,您从标准中引用的内容没有具体引用int 类型。不,int 不能保证足以在 C 中存储任何对象(包括数组)的大小。

    其次,C 语言实际上并没有专门的“数组订阅”。数组订阅是通过指针算法实现的。并且指针算术中的整数操作数具有ptrdiff_t 类型。不是size_t,不是int,而是ptrdiff_t。它是有符号类型,顺便说一句,这意味着该值可以为负数。

    第三,size_t的目的是存储程序中任意对象的大小(即存储sizeof的结果)。它不会立即用作数组索引。它恰好作为数组索引工作,因为它保证它总是足够大以索引任何数组。但是,从抽象的角度来看,“数组”是一种特定的“容器”,还有其他类型的容器(基于列表的容器、基于树的容器等等)。在一般情况下,size_t 不足以存储 any 容器的大小,这在一般情况下也使其成为数组索引的一个值得商榷的选择。 (另一方面,strlen 是一个专门用于数组的函数,这使得 size_t 适合在那里。)

    【讨论】:

    • 鉴于 callocqsortfread/fwrite 都使用成对的 size_t 值来表示元素大小和元素数量,我不同意你的说法,即 size_t不打算用作数组索引。指针算术中的整数操作数也可以是任意整数类型,不仅仅是ptrdiff_t,而是指针相减的结果类型为ptrdiff_t
    • @Vladislav Vaintroub:不能。 size_t 根据定义可以容纳您的实现允许您创建的最大连续对象的大小。这就是它所能做的。无法保证您可以创建一个占用整个内存的对象,因此无法保证size_t 足以索引整个内存。可以索引整个内存的整数类型称为uintptr_t,而不是size_tsize_t 通常情况下小于“整个内存”。
    • 分段内存平台通常会有这样的“小”size_t,如 DOS/Win16 或 IBM 128 位平台。这些是我的“反例”。但是,我不在乎任何“反例”。反例并不重要。重要的是size_t 实现了一个非常具体的概念。这个概念与通用计数无关。这立即使size_t 不适用于通用计数。是否“足够”根本不重要。
    • 6.5.6/9:说到指针减法,“如果结果在 [ptrdiff_t] 中不可表示,则行为未定义”。由此可见,ptrdiff_t保证足够大以包含对象中的任何偏移量。 ptrdiff_t 是指针算术中的“整数操作数”也是错误的。任何整数类型都可用于指针加法,标准仅使ptrdiff_t 成为减法的特例。 size_t 是定义为可用于对象中任何正偏移的类型,而不是 ptrdiff_t。它不会“发生”工作,它被定义为。 offsetof 也使用它
    • @AndreyT:对象大小和元素计数并非完全不相关的概念。 in elements 数组的大小等于其元素数。数组的大小 以字节为单位 等于其元素计数乘以每个元素的大小(以字节为单位)。这就是数组。可能有一些更高的抽象,您希望将数组视为特殊情况,但 C 语言不会,因此您的偏好与 C 几乎没有关系,当然也不能证明每个人都停止使用 size_t 来做它的设计目的。也许是其他语言。
    【解决方案4】:

    在编写 C 标准时,机器通常具有 16 位“int”类型,并且无法处理任何大于 65535 的单个对象 字节,但仍然能够处理大于 32767 字节的对象。 由于无符号整数上的算术足以处理最大的 此类对象的大小,但对有符号整数的算术不会,定义了 size_t 未签名以便容纳此类对象而不必使用“long” 计算。

    在最大允许对象大小介于 INT_MAX 和 UINT_MAX,指向此类的开始和结束的指针之间的差异 对象可能太大而无法放入“int”。虽然标准没有强加 关于实现应该如何处理的任何要求,一种常见的方法 是定义整数和指针环绕行为,使得如果 S 和 E 是指向 char[49152] 开头和结尾的指针,那么即使 E-S 将超过 INT_MAX,它将产生一个值,当添加到 S 时,将 产量E。

    如今,size_t 是 无符号类型(因为需要大于 2GB 的对象的代码通常会 由于其他原因需要使用 64 位指针),它会导致多种 涉及对象大小的比较行为违反直觉,但 sizeof 表达式产生无符号类型的事实已经足够好 根深蒂固地认为它永远不会改变。

    【讨论】:

      【解决方案5】:

      size_t 是无符号整数的 typedef(例如 int 或 long)。

      在一些64位平台中,int可以是32位,而size_t可以是64位。

      它被用作更标准的尺寸方式。

      【讨论】:

      • “size_t 是 unsigned int 的 typedef。” - 并非总是如此。
      • 不,size_t 是一些无符号类型的 typedef。隐藏在size_t 后面的类型甚至可能是非标准的,即它可能无法表达为unsigned intunsigned long 等。
      • 理论上,size_t 可能是unsigned long long 甚至是uintmax_t
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      相关资源
      最近更新 更多