ptrdiff_t可以表示指向同一数组对象元素的所有指针的减法吗?

jot*_*tik 32 c++ arrays pointer-arithmetic language-lawyer ptrdiff-t

对于指针的减法ij同一数组对象元素,[expr.add#5]中的注释读取:

[  注意:如果值i-j不在类型的可表示值范围内std?::?ptrdiff_­t,则行为未定义.-  结束说明 ]

但是给出[support.types.layout#2],其中指出(强调我的):

  1. 该类型ptrdiff_­t是一个实现定义的有符号整数类型,它可以保存数组对象中两个下标的差异,如[expr.add]中所述.

结果是否可能i-j不在可表示的值的范围内ptrdiff_t

PS:如果我的问题是由于我对英语的理解不足造成的,我道歉.

编辑:相关:为什么数组的最大大小"太大"?

YSC*_*YSC 5

结果是否可能i-j不在可表示的值的范围内ptrdiff_t

是的,但不太可能.

事实上,[support.types.layout]/2并没有说话,除了指点一下减法适当的规则和ptrdiff_t中定义[expr.add].那么让我们看看这一节.

[expr.add]/5

当减去指向同一数组对象的元素的两个指针时,结果的类型是实现定义的有符号整数类型; 此类型应std?::?ptrdiff_­t<cstddef>标题中定义的类型相同.

首先,请注意,这里的情况ij不同的阵列的标指标不考虑.这允许以治疗i-jP-Q将是其中P是一个指针阵列中的下标元素iQ是指向的元件相同的在标数组j.实际上,减去两个指向不同数组元素的指针是未定义的行为:

[expr.add]/5

如果表达式PQ指向,分别,元件x[i]x[j]同一阵列对象的x,表达P - Q具有值i?j ; 否则,行为未定义.

作为结论,使用先前定义的符号,i-j并且P-Q被定义为具有相同的值,后者是类型std::ptrdiff_t.但没有人说这种类型存在这种价值的可能性.但是,可以在以下帮助下回答这个问题std::numeric_limits; 特别是,可以检测数组some_array是否太大std::ptrdiff_t无法容纳所有索引差异:

static_assert(std::numeric_limits<std::ptrdiff_t>::max() > sizeof(some_array)/sizeof(some_array[0]),
    "some_array is too big, subtracting its first and one-past-the-end element indexes "
    "or pointers would lead to undefined behavior as per [expr.add]/5."
);
Run Code Online (Sandbox Code Playgroud)

现在,在通常的目标上,这通常不会发生sizeof(std::ptrdiff_t) == sizeof(void*); 这意味着一个数组需要很大ptrdiff_t才能溢出.但不能保证.

  • 有趣的方面:​​假设size_t和ptrdiff_t具有相同的大小,因为前者是无符号的,但后者是有符号的,它可以用于定义大于指针差异可以容纳的数组.标准对此有何看法?如果*any*difference*必须*可以表示,我们必须得出结论(可能没有实际提到)数组大小不得超过`std :: numeric_limits <std :: ptrdiff_t> :: max()`,无论如何如果`std :: size_t`能够保存这样的值...... (4认同)
  • @Aconcagua在16位平台上禁用"大"数组是相当不切实际的.您可以选择64K字节的数据存储器,但只有32K字节的最大阵列大小,或者宽于16位的ptrdiff_t,这两种情况都是不可取的.所以UB就是这样. (3认同)
  • 不,support.types.layout没有说任何这样的事情.它表示"......如expr.add"中所述"和expr.add描述了ij不可表示的情况l. (2认同)
  • 这并不能真正回答问题 (2认同)