【问题标题】:size_t ptrdiff_t and address spacesize_t ptrdiff_t 和地址空间
【发布时间】:2019-01-26 19:51:21
【问题描述】:

在我的系统上,ptrdiff_tsize_t 都是 64 位

我想澄清两点:

  • 我相信由于地址空间的限制,没有数组可以像size_t 这样大。这是真的吗?

  • 如果是,那么是否可以保证ptrdiff_t 能够保存最大大小数组中any 指针的减法结果?

【问题讨论】:

  • 不是指针差异,而是索引减法的结果。
  • 对于 ptrdiff_t 到 "overflow" ,对象大小必须为 1(字符大小)。对于对象大小 > 2,一切正常。
  • @RobertAndrzejuk,对不起,如果我不够清楚。我的意思是:“指向数组元素的指针”。
  • 我也想引起您的注意,(使用@NathanOliver 引号)给定定义long long arr[2],然后减法&arr[1] - &arr[0] 得到结果1(而不是4可能是预期的)。因此,要解决这个“溢出”问题,您必须处理原始内存(1 字节大小的类型)。
  • @RobertAndrzejuk,感谢您指出这一点!

标签: c++ pointers size memory-address


【解决方案1】:

不,没有这样的保证。例如,请参见此处:https://en.cppreference.com/w/cpp/types/ptrdiff_t

如果数组太大(大于 PTRDIFF_MAX 个元素,但小于 大于 SIZE_MAX 字节),两个指针之间的差异可能不 可表示为 std::ptrdiff_t,减去两个这样的结果 指针未定义。

【讨论】:

    【解决方案2】:

    大多数实现人为地限制最大数组大小,以确保指向同一数组的两个指针之间的差异适合ptrdiff_t。因此,在您的平台上,允许的最大数组大小很可能约为SIZE_MAX / 2(试试看)。这不是“地址空间限制”,它只是您的实现在内部强制执行的限制。在这个限制下,合法的指针减法(“合法”=两个指针指向同一个数组)不会溢出。

    但语言规范并不要求这样做。实现不需要以这种方式限制它们的数组大小,这意味着语言规范允许看似合法的指针减法溢出并产生未定义的行为。但大多数实现更喜欢通过限制数组大小来防范这种情况。

    更多详情请参见此处的“三个选项”:Why is the maximum size of an array "too large"?

    【讨论】:

    • 确实!编译以下代码:char array[SIZE_MAX/2+1]; 导致错误:数组'array'的大小太大
    【解决方案3】:

    来自 [support.types.layout]/3

    size_t 类型是实现定义的无符号整数类型,其大小足以包含任何对象的字节大小。

    所以你可以保证size_t 可以容纳你可以拥有的最大数组的大小。

    ptrdiff_t 不幸的是不能保证。来自 [support.types.layout]/2

    ptrdiff_t 类型是实现定义的有符号整数类型,可以保存数组对象中两个下标的差异,如 8.7 中所述。

    这没关系,但我们有 [expr.add]/5

    当两个指向同一个数组对象的元素的指针相减时,结果的类型是实现定义的有符号整数类型;此类型应与标头 (21.2) 中定义为 std::ptrdiff_t 的类型相同。如果表达式 P 和 Q 分别指向同一个数组对象 x 的元素 x[i] 和 x[j],则表达式 P - Q 的值为 i - j;否则,行为未定义。 [ 注意:如果值 i - j 不在 std::ptrdiff_t 类型的可表示值范围内,则行为未定义。 ——尾注]

    这表明ptrdiff_t 可能不够大。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-02
      • 1970-01-01
      • 2015-07-28
      • 2018-05-08
      • 2014-08-15
      • 2017-08-11
      相关资源
      最近更新 更多