当我减去内存地址时,为什么结果比我预期的要小?

When I subtract memory addresses, why is the result smaller than I expected?

本文关键字:结果 为什么 内存 地址      更新时间:2023-10-16

我有以下程序:

#include <iostream>
struct X
{
    int a;
    float b;
} x[10], *p1, *p2;
int main(int argc, char *argv[])
{
    p1 = &x[1];
    p2 = &x[5];
    int i = p2 - p1;
    std::cout << i << std::endl;
}

我可以想象X在内存中的布局,包含一个int和一个float的10个盒子,p1将指向第二个盒子(x[1])的开始,p2指向第六个盒子(x[5])的开始:

   X   0   1  2  3  4  5  6  7  8  9
       _______________________________
    b  |__|__|__|__|__|__|__|__|__|__|
    a  |__|__|__|__|__|__|__|__|__|__|
          |           |    
          |           | 
          p1          p2

我的画对吗?如果是这样,为什么i的结果是4 ?
理解两个地址的减法有困难吗?

这就是指针运算的工作原理。考虑:

p1 = (x*)100;   // invalid memory address, just an example!
p2 = p1 + 1; 

此时,p2的值不是101,而是100 + sizeof(x)(假设是8,所以是108)。它不是增加了1,而是增加了sizeof(x)的1倍!相反,从指针中减去整数实际上减去了sizeof(the pointed to type)倍。

所以现在如果你执行int diff = p2 - p1,你肯定会期望得到1,而不是8 !否则,减去刚刚添加的数字不会得到原始值。因此,从另一个指针中减去一个指针产生的不是内存地址的差异,而是两个指针之间的元素数量的差异。

此外,标准规定指针的减法是没有意义的,除非两个指针指向同一个数组中的元素(更准确地说,这是未定义的行为,即使没有这样的对象,也允许使用指向"最后一个元素的倒数一"的指针)。

最后,如果编译器不知道指向类型的大小(即指针是void*)怎么办?在这种情况下,根本不允许使用指针算术。例如:

void* p = 100;
void* x = p + 1; // does not compile¹

¹一些编译器可能会在void*上提供指针运算,作为语言规范的扩展。在这种情况下,该语句确实可以编译,结果将取决于所述扩展的规范(例如,gcc将以值101结束)。

相关文章: