为什么不能将两个地址加在一起?

Why is it not possible to add two addresses together?

假设我定义了两个变量 xy:

int x = 5;
int y = 6;

我可以通过以下方式获取存储 x 的地址:

cout << &x << endl; // 0x61fe18

这是一个十六进制数。现在,如果我想在加 5 后打印这个数字,这很简单:

cout << &x + 5 << endl; // 0x61fe1d

但是如果我将 xy 的地址加在一起:

cout << &x + &y << endl;

我得到一个错误:

invalid operands of types 'int*' and 'int*' to binary 'operator+'
cout << &x + &y << endl;
        ~~~^~~~

为什么我不能添加这两个地址?

简短回答:因为 C++ 标准是这么说的。

长答案:因为它没有意义。从来没有将两个地址加在一起会产生任何用处的情况。

当您向地址添加(或减去)整数偏移量时,您将到达位于地址的给定偏移量处的对象。非常有用,基本上是所有数组操作的基础。

但是,如果将两个地址相加,我们就会到达内存中一个完全随机的位置,您不可能希望从中找到任何有价值的东西。因此,语言不允许您这样做,并且编译器拒绝编译此代码。

但是,如果您只需要两个地址的数值表示之和的数值表示(例如,对于复杂的 运行-time 混淆),这可以使用专门设计的类型来完成为此:uintptr_t。以下是有效代码:

auto z = uintptr_t(&x) + uintptr_t(&y);

能够将某物转换为整数并不意味着它就是整数。

计算机使用二进制逻辑,您可以采用二进制形式的任何信息并将其转换为整数。但它是一个整数,就意味着加减乘除都具有预期的意义。

指针存储为二进制数据,但许多操作对它们没有意义。

我在地球上的位置可以用一对 lat/long 数字表示。那对数字不是我在地球上的位置

数字相加是合理的运算。将位置加在一起是无稽之谈。

“纽约的位置”加上“莫斯科的位置”没有意义。

“纽约纬度”加上“莫斯科纬度”是一个数字,但这个数字基本上是胡说八道,纽约Lat/Long值之和的一对Lat/Long值莫斯科也一样。

纽约市和莫斯科之间的中点确实有意义,但其中有两个(世界的另一端)。此外,纽约市和莫斯科之间 25% 的路程是合理的。

接下来“从纽约市到莫斯科的最短路径”是一个向量。它不是一个位置,而是地球表面的一个方向。您可以获取该矢量并将其添加到另一个位置——“如果我从多伦多开始会怎么样”——然后获得一个新位置。

指针是位置,例如“NYC”和“Moscow”。当您添加到指针时,该整数在指针位置 space 上充当 向量

C++ 试图使无意义的操作不会发生,除非您强制执行。添加指针——添加位置——是无稽之谈。向指针添加一个整数是有意义的。取两个指针之间的差异是有道理的。

当您打印出一个指针时,编译器会使用 std::ostream& << void*void* 重载。此重载用于调试目的,并将指针的位解释为十六进制整数。

您可以通过将指针转换为 std::uintptr_t 来手动执行此操作——一种保证足够大以存储指针位的无符号整数类型。


您会注意到,当您执行 &x + 5 时,您得到的整数不会比您执行 &x 时大 5。其实就是&x + sizeof(x)*5.

这是因为指针算法假设您正在处理一个数组,并且将 forward/backwards 移动一个对象大小。

std::cout << &x << std::endl; // 0x61fe18
std::cout << (&x + 5) << std::endl; // 0x61fe1d

只有 xsizeof(x)==1 时才会发生这种情况。正如您声称 x 是一个 int,这在 C++ 中是不可能的。

如果sizeof(int)4(现在很常见),

std::cout << &x << std::endl; // 0x61fe18
std::cout << (&x + 5) << std::endl; // 0x61fe2c

是你会得到的。

这是因为指针不是整数。能够将它们打印为整数并不意味着它们是整数。