请考虑以下代码:
char* p = new char[2];
long* pi = (long*) p;
assert(p == pi); // OK
char* p1 = &p[1];
long* pi1 = (long*) p1;
assert(p1 == pi1); // OK
int d = p1 - p;
int d1 = pi1 - pi;
assert(d == d1); // No :(
运行后,我得到d == 1
和d1 == 0
,虽然p1 == pi1
和p == pi
(我在调试器中检查了这一点)。这是未定义的行为吗?
答案 0 :(得分:10)
正如其他人指出的那样,这是未定义的行为。但是,对于您所看到的内容有一个非常简单的解释。
指针之间的区别在于元素的数量,而不是它们之间的字节数。
pi和pi1都指向long,但pi1指向的地址仅比pi大一个字节。假设long是4个字节长,地址的差值1除以元素4的大小为0。
另一种思考方式是你可以想象编译器会生成与此相当的代码来计算d1:
int d1 = ((BYTE*)pi1 - (BYTE*)pi)/sizeof(long).
答案 1 :(得分:5)
如果指针没有指向同一个数组,或者指针是从指向不相关类型的指针进行类型转换,则两个指针之间的区别是未定义的。
此外,差异不是字节数,而是元素数。
在第二种情况下,差异是1个字节,但它除以sizeof(long)。请注意,因为这是未定义的行为,所以这里的任何答案都是正确的。
答案 2 :(得分:2)
重新解释指针的基础类型不会更改其地址。但指针算术会根据指针类型产生不同的结果。所以你在这里描述的是完全正确的,这就是我所期望的。请参阅pointer arithmetics。
答案 3 :(得分:0)
它为pi1 - pi
执行整数(长)指针算术;
如果p1
为&p[4]
,您会看到它为1
打印d1
,而差异实际为4个字节。这是因为sizeof (long)
= 4个字节。