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

这是我的“我不理解C和C ++中的指针”集合中的一个新问题。

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

#include  #include  #include  // 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:%pb:%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; } 

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

也可以看看

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

  • 指针的memcpy与赋值相同吗? 这是我的另一个问题的变体:
  • 取消引用包含对象地址(数组数组)的出界指针

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

  • 指针变量只是与某些运算符整数还是“神秘”?
  • 和C ++问题: 用相同类型的对象覆盖对象

在[basic.compound]中:

如果类型T的对象位于地址A ,则类型为cv T*的指针(其值为地址A被称为指向该对象, 而不管该值是如何获得的

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


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

指针类型的每个值都是以下之一:
指向对象或函数的指针(指针指向对象或函数),或
指针超过对象的末尾 (5.7),或
– 该类型的空指针值 (4.11),或
无效的指针值

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

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

past并没有指向某种东西,因此将其内容视为与val相同并不再有意义。

第二个断言

 assert(memcmp(&a, &b, s) == 0); 

可以合法地失败,因为比较相等的指针不需要具有相同的表示。

一旦这个断言被传递,其他一切memcpy ,因为memcpy是一种复制指针的合法方式。 在现代C ++中 – 说,指针是可以轻易复制的。 允许从字节组装这些对象,这些字节的来源无关紧要。

如果两个这样的对象是memcmp相等的,它们保持相同的值(强于“比较相等”:它们是可互换的,而比较相等的指针不需要)。 至少这样是标准的精神,我不会担保这封信。

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

对象p包含一个值,该值对应于内存中对象x的位置。

而已。 这就是它的意思。 你似乎决心让它变得比它需要的更复杂。

指针类型不是算术类型,并不意味着像这样任意地使用。 有效的指针值是通过在左值上使用一元&运算符,使用不是sizeof或一元&运算符的操作数的数组表达式,或者调用返回指针值的库函数来获得的。

除此之外的一切 (大小,表示,物理与虚拟等)都是一个实现细节 ,并且在表示地址时实现的差异很大 。 这就是为什么当你用指针值玩弗兰肯斯坦博士时,标准没有说明会发生什么

如果您非常熟悉平台的寻址约定(虚拟和物理),并且您知道实现如何在内存中布置项目以及它如何表示指针类型,并且您有一个有效的用例来通过这种方式来攻击指针值,然后劈开你心中的内容 – 语言标准都没有任何关于这个主题的说法。