如果操作数指向对象的数据成员但是在整个数组边界内,指针子行为是否定义良好?

时间:2012-02-21 09:58:10

标签: c

struct Item {
    int i;
    char * x;
};
Item all[] = { {0, "0"},  {1, "1"},  {2, "2"}, };

int i = all - (Item *) &all[2].x ;
printf("i = %d\n", i);

在上面的代码中,我将&all[2].x转换为(Item*)并执行指针子句操作, mingw g ++(4.6.1)生成-2,VC2010生成-3

这样的操作是一个明确定义的行为(然后VC可能有一个bug,无论如何两个指针之间的距离是2个元素)或不是?

我搜索ANSI C标准(C99)6.5.6语义(9)说:

  

当减去两个指针时,两个指针都指向同一个数组对象的元素,   或者超过数组对象的最后一个元素;结果是差异   两个数组元素的下标。

指向对象的数据成员是否也是不正确的(不应该暗示)。

我还查了<>第7.6.2节添加剂操作/替代,说:

  

......只有在结果明确且可移植的情况下   两个指针指向同一个数组中的对象或指向一个超过最后一个对象的对象   阵列。

看起来指针必须指向对象本身,指向对象的数据成员没有明确定义。但该声明并未明确声明。

another resource说:

 ( p2 - p1 ) == ( addr( p2 ) - addr( p1 ) ) / sizeof( T )
     

...

     

p2p1无需指向数组中的有效元素。即使p2p1包含无效地址(因为它们包含某些地址),上述公式仍然有效。

让我更加困惑。

有人请澄清这个微妙的问题吗?

3 个答案:

答案 0 :(得分:2)

您无法将x的地址强制转换为Item *,因为它不会指向Item的开头(之前还有其他成员)。

可以i成员的地址转换为Item *

答案 1 :(得分:2)

您从标准中引用的部分很清楚:

  

当减去两个指针时,两个指针都应该指向   相同的数组对象...

&all[2].x 指向数组all的元素。指向元素的子对象并不指向元素。

这意味着行为未定义。

答案 2 :(得分:1)

----iiiippppiiiippppiiiipppp----
    \------/\------/\------/
     all[0]  all[1]  all[2]

                        |                  &all[2].x
    |       |       |       |           <= &all[0], [1], [2], [3]

&all[2].x与任何&all[??]之间不匹配。