代码之家  ›  专栏  ›  技术社区  ›  Sergey

两种不同缓冲区的指针算法

  •  47
  • Sergey  · 技术社区  · 6 年前

    请考虑以下代码:

    int* p1 = new int[100];
    int* p2 = new int[100];
    const ptrdiff_t ptrDiff = p1 - p2;
    
    int* p1_42 = &(p1[42]);
    int* p2_42 = p1_42 + ptrDiff;
    

    现在,标准是否保证 p2_42 指向 p2[42] ?如果不是,在Windows、Linux或Webassembly堆上是否总是这样?

    4 回复  |  直到 6 年前
        1
  •  52
  •   Max Langhof    6 年前

    要添加标准报价:

    expr.add#5

    当两个指针表达式 P Q 减去后,结果的类型是实现定义的有符号整数类型;此类型应与定义为 std::ptrdiff_­t <cstddef> 头([支持类型])。

    • (5.1) 如果 Q 两者都计算为空指针值,结果为0。

    • (5.2) 否则,如果 Q 分别指向元素 x[i] x[j] 相同数组对象的 x ,表达式 P - Q 具有价值 i−j .

    • (5.3) 否则,行为是未定义的。 [艾斯] 注: 如果值 我爱你 不在类型的可表示值范围内 标准::ptrdiff_t ,行为未定义。 尾注 埃斯·阿

    (5.1)不适用,因为指针不是空指针。(5.2)不适用,因为指针不在同一数组中。所以,我们只剩下(5.3)-ub了。

        2
  •  28
  •   Language Lawyer    6 年前
    const ptrdiff_t ptrDiff = p1 - p2;
    

    这是未定义的行为。只有当两个指针指向同一数组中的元素时,才能很好地定义它们之间的减法。( [expr.add] ¶5.3 )

    当两个指针表达式 P Q 减去后,结果的类型是实现定义的有符号整数类型;此类型应与定义为 std::ptrdiff_­t <cstddef> 头([支持类型])。

    • 如果 Q 两者都计算为空指针值,结果为0。
    • 否则,如果p和q分别指向元素 x[i] x[j] 相同数组对象的 x ,表达式 P - Q 具有价值 i−j .
    • 否则,行为是未定义的

    即使有一些假设的方法以合法的方式获得这个值,即使求和也是非法的,因为即使指针+整数求和也被限制在数组的边界内。( [expr.add] ¶4.2 )

    当一个表达式 J 在表达式中加上或减去具有整型的 指针类型的,结果的类型为 .

    • 如果 计算为空指针值并 J 计算结果为0,结果为空指针值。
    • 否则,如果 指向元素 x[i] 数组对象的 X 有n个元素, 八十一 表达式 P + J J + P (何处) J 具有价值 j )指向(可能是假设的)元素 x[i+j] 如果 0≤i+j≤n 以及表达 P - J 指向(可能是假设的)元素 x[i−j] 如果 0≤i−j≤n .
    • 否则,行为是未定义的。
        3
  •  9
  •   MSalters    6 年前

    第三行是未定义的行为,因此标准允许在此之后进行任何操作。

    只允许减去指向同一数组(或同一数组之后)的两个指针。

    Windows或Linux并不真正相关;编译器尤其是它们的优化器会破坏程序。例如,优化器可能认识到 p1 p2 两者都指向 int[100] 所以 p1-p2 必须是0。

        4
  •  7
  •   supercat    6 年前

    该标准允许在将内存划分为离散区域的平台上实现,这些区域不能通过指针算法相互访问。作为一个简单的例子,一些平台使用24位地址,这些地址由一个8位的银行编号和一个银行内的16位地址组成。将一个地址添加到标识一个银行的最后一个字节的地址中,将产生指向该地址第一个字节的指针。 相同的 银行,而不是 下一个 银行。这种方法允许使用16位数学而不是24位数学计算地址算术和偏移量,但要求没有对象跨越一个银行边界。这样的设计会给 malloc ,并且可能导致比其他情况下更多的内存碎片,但是用户代码通常不需要关心将内存分区到存储库中。

    许多平台没有这样的体系结构限制,一些专为此类平台上的低级编程而设计的编译器将允许在任意指针之间执行地址算法。该标准指出,处理未定义行为的一种常见方法是“在翻译或程序执行过程中以文档化的方式以环境的特征进行行为”,并且在支持通用指针算法的环境中支持它将很好地适应该类别。不幸的是,该标准未能提供任何方法来区分以这种有用方式运行的实现和不以这种方式运行的实现。