取消引用50%的出界指针(数组数组)

cur*_*guy -2 c c++ arrays pointers language-lawyer

这是我在"我不理解C和C++中的指针"集合中的一个新问题.

如果我将具有相同值的两个指针的位混合(指向相同的存储器地址),那恰好具有完全相同的位表示,当一个是可解除引用且一个是结束时,标准说应该发生什么?

#include <stdio.h>
#include <string.h>
#include <assert.h>

// required: a == b
// returns a copy of both a and b into dest 
// (half of the bytes of either pointers)
int *copy2to1 (int *a, int *b) {
    // check input: 
    // not only the pointers must be equal
    assert (a == b);
    // also the representation must match exactly
    int *dest;
    size_t s = sizeof(dest);
    assert(memcmp(&a, &b, s) == 0); 

    // copy a and b into dest:
    // on "exotic" architectures, size does't have to be dividable by 2
    size_t half = s/2; // = floor(s/2), 
    char *pa = (char*)&a, *pb = (char*)&b, *pd = (char*)&dest;

    // copy half of a into dest:
    memcpy (pd, pa, half);
    // copy half of b into dest:
    memcpy (pd+half, pb+half, s-half); // s-half = ceil(s/2)

    //printf ("a:%p b:%p dest:%p \n", a, b, dest);    

    // check result
    assert(memcmp(&dest, &a, s) == 0);
    assert(memcmp(&dest, &b, s) == 0);

    return dest;
}

#define S 1 // size of inner array

int main(void) {
    int a[2][S] = {{1},{2}};
    int *past = a[0] + S, // one past the end of inner array a[0]
        *val = &a[1][0], // valid dereferenceable pointer
        *mix = copy2to1 (past, val);
    #define PRINT(x) printf ("%s=%p, *%s=%d\n",#x,x,#x,*x)
    PRINT(past);
    PRINT(mix);
    PRINT(val);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我真正想要理解的是:"p指向对象x"是什么意思?

也可以看看

这个问题是我之前关于数组数组问题的更好的版本:

和指针有效性的其他相关问题:

Bar*_*rry 9

在[basic.compound]中:

如果类型的对象T位于地址A,则表示值为地址的类型为cv T*的指针A将指向该对象,而不管该值是如何获得的.

past并且val具有相同的地址,因此它们指向同一个对象.一个是"第一行的一个结束"并且第二个是第二行的第一个元素并不重要.该地址有一个有效的对象,所以这里的一切都是完全合理的.


在C++ 17中,从P0137开始,这种情况发生了很大的变化.现在,[basic.compound]将指针定义为:

指针类型的每个值是下列之一:
-一个指针的对象或函数(指针被说成指向的对象或功能),或
- 一个指针过去的端部的对象(5.7),或
-所述该类型的空指针值(4.11),或
- 无效的指针值.

所以现在,past是第二种类型的值(超过结尾的指针),但是val第一种类型的值(指向).这些是不同类别的价值观,不具有可比性:

指针类型的值是指向或超过对象末尾的指针,表示对象占用的内存中的第一个字节的地址(1.7)或者在对象占用的存储结束后内存中的第一个字节的地址, 分别.[注意:超过对象末尾的指针(5.7)不被视为指向可能位于该地址的对象类型的无关对象.当指示的存储达到其存储持续时间的末尾时,指针值变为无效; 见3.7. - 尾注]

past没有指向什么,所以查看它的内容就好像它是相同的val不再有意义.

  • ......但他们被允许这样做.指针`a [0] + 5`和`a [1]`将比较相等,但前者是一个过去的指针,用于'a [0]`而第二个是指向a的第一个元素的指针[1]`.如果标准要求指针上的某些操作必须导致编译器"忘记"它可能对其行为产生的任何限制,那将会很有帮助,但在这些问题上却相当模糊. (2认同)