为什么这两个指针减法给出不同的结果?

Why do these two pointer subtractions give different results?

提问人:Luchian Grigore 提问时间:2/8/2012 最后编辑:Russell BorogoveLuchian Grigore 更新时间:2/8/2012 访问量:449

问:

请考虑以下代码:

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 == 1d1 == 0p1 == pi1p == pi

C++语言

评论

1赞 Mysticial 2/8/2012
如果您查看反汇编,则会产生一个减法,然后右移 2 位。(在 MSVC 上)这种右移显然是除以除,当然会截断为 0,相差仅为 1。我不知道这种行为是否被定义。pi1 - pisizeof(long)

答:

5赞 Mark Ransom 2/8/2012 #1

如果指针不指向同一数组,或者指针是从指向不相关类型的指针类型转换的,则两个指针之间的差异是未定义的。

此外,区别不在于字节,而在于元素的数量。

在第二种情况下,差值是 1 个字节,但它被除以 sizeof(long)。请注意,由于这是未定义的行为,因此此处的任何答案都绝对是正确的。

评论

0赞 2/8/2012
伙计,我看着你的头像笑了:)这是一个绝妙的主意:)))
2赞 Seth Carnegie 2/8/2012
在哪个部分中,您不能对从不相关类型转换的指针进行指针算术运算
0赞 Mark Ransom 2/8/2012
@SethCarnegie,我不能指出任何具体的东西,事实上我可能弄错了。我认为类型转换本身生成了 UB,尤其是在这种情况下,因为它与类型未对齐。
0赞 Seth Carnegie 2/8/2012
啊,你是对的。(对于任何想知道的人,我认为这在§5.2.10.7中都有详细说明)
2赞 user405725 2/8/2012 #2

重新解释指针的基础类型不会更改其地址。但是指针算术会根据指针类型产生不同的结果。所以你在这里描述的是完全正确的,这就是我所期望的。请参阅指针算术

0赞 jman 2/8/2012 #3

它做整数(长)指针算术pi1 - pi;

如果是这样,你会看到它打印了,而差异实际上是 4 个字节。这是因为 = 4 个字节。p1&p[4]1d1sizeof (long)

评论

0赞 Grizzly 2/8/2012
的大小取决于平台,因此差异可能是即使指向(或者可能是或其他东西)。事实上,许多 64 位平台都有 8byte .IIRC 甚至存在平台,其中 ( 例如 在那些)long0p1&p[4]4longsizeof(long)==1char64bit
10赞 Michael 2/8/2012 #4

正如其他人所指出的,这是未定义的行为。但是,对于您所看到的内容,有一个非常简单的解释。

指针之间的区别在于元素的数量,而不是它们之间的字节数。

pi 和 pi1 都指向 longs,但 pi1 指向的地址只比 pi 多一个字节。假设 long 的长度为 4 个字节,则地址的差值 1 除以元素的大小 4 为 0。

另一种思考方式是,您可以想象编译器将生成与此等效的代码来计算 d1:

int d1 = ((BYTE*)pi1 - (BYTE*)pi)/sizeof(long).