为啥这两个指针减法会给出不同的结果?
Posted
技术标签:
【中文标题】为啥这两个指针减法会给出不同的结果?【英文标题】:Why do these two pointer subtractions give different results?为什么这两个指针减法会给出不同的结果? 【发布时间】:2012-02-07 22:44:56 【问题描述】:考虑以下代码:
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
(我在调试器中检查了这个)。这是未定义的行为吗?
【问题讨论】:
如果你看一下反汇编,pi1 - pi
产生一个减法,然后右移 2 位。 (在 MSVC 上)右移显然是除以 sizeof(long)
,它当然会截断为 0,相差仅为 1。我不知道是否定义了这种行为。
【参考方案1】:
正如其他人所指出的,这是未定义的行为。但是,对于您所看到的内容,有一个非常简单的解释。
指针之间的区别在于元素的数量,而不是它们之间的字节数。
pi 和 pi1 都指向 longs,但 pi1 指向的地址仅比 pi 多一个字节。假设 long 的长度为 4 个字节,则地址差 1 除以元素的大小 4 为 0。
另一种思考方式是,您可以想象编译器会生成与此等效的代码来计算 d1:
int d1 = ((BYTE*)pi1 - (BYTE*)pi)/sizeof(long).
【讨论】:
【参考方案2】:如果两个指针不指向同一个数组,或者指针是从指向不相关类型的指针类型转换的,则两个指针之间的差异是不确定的。
另外,区别不在于字节,而在于元素的数量。
在您的第二种情况下,差异是 1 个字节,但它被 sizeof(long) 除。请注意,因为这是未定义的行为,所以这里的任何答案都是正确的。
【讨论】:
伙计,我看着你的头像笑了:) 这是一个绝妙的主意:))) 在哪一节中说你不能对从不相关类型转换的指针进行指针运算 @SethCarnegie,我无法指出任何具体的内容,事实上我可能弄错了。我认为类型转换本身会生成 UB,尤其是在这种情况下,因为它与类型未对齐。 啊,你是对的。 (对于任何想知道的人,我认为这在 §5.2.10.7 中有详细说明)【参考方案3】:重新解释指针的底层类型不会改变它的地址。但是指针算术会根据指针类型产生不同的结果。所以你在这里描述的是完全正确的,这就是我所期望的。见pointer arithmetics。
【讨论】:
【参考方案4】:它为pi1 - pi
做整数(长)指针运算;
如果p1
是&p[4]
,您会看到它为d1
打印1
,而实际差异是4 个字节。这是因为sizeof (long)
= 4 个字节。
【讨论】:
long
的大小取决于平台,因此即使p1
指向&p[4]
(或者可能是4
或其他),差异也可能是0
。事实上,许多 64 位平台都有 8byte long
。 IIRC 甚至存在sizeof(long)==1
的平台(char
是例如64bit
在那些)以上是关于为啥这两个指针减法会给出不同的结果?的主要内容,如果未能解决你的问题,请参考以下文章
Python append() 与列表上的 + 运算符,为啥这些会给出不同的结果?
Python append() 与列表上的 + 运算符,为啥这些会给出不同的结果?
为啥 innerHTML 和 textContent 给出不同的结果?