将 1 添加到地址会导致将 0xE0 添加到该地址

Adding 1 to an address result in adding 0xE0 to that address

我在尝试向使用 & 运算符获得的地址添加偏移量时遇到了一个非常奇怪的行为。 因此,当我尝试向该地址添加任何数字时,结果是该地址加上我的数字乘以 0xE0 (224).

这些是Visual Studio中关注列表的截图。 每张截图的第一行是我的对象地址的访问,是正确的。 第二行是相同的访问,但我们向其添加了变量偏移量。 第三行只是偏移量本身。

如您所见,第一个屏幕截图上的一切都很好。但是在第二个上,加法是 0xE0 (0xE38-0xD58=0x0E0) 而不是应该的 1 。在最后一张截图中添加的是 0x1C02*0xE0.

在第 2 行,我希望在第一个屏幕截图中看到 0x00000255ef9bed58,在第二个屏幕截图中看到 0x00000255ef9bed59,在最后一个屏幕截图中看到 0x00000255ef9bed5a

给定 t *my_ptr = get_a_pointer_somehow();int my_num = get_a_number_somehow();,当您执行 my_ptr += my_num 时,它将指针前进 tmy_num,或者换句话说,添加my_num * sizeof(t) 字节。如果您不想要这种行为,则首先将指针转换为 char *,因为 sizeof(char) 始终为 1。

指针不是整数。指针运算不同于整数运算。向指针加 1 并不意味着 "give me the neighboring address"。指针加 1 表示 "give me the address of the neighbouring object within the array"。相邻物体之间的距离与物体的大小相同。如果该大小大于一个字节,则相邻对象相距几个字节。

在这种情况下,如果您的计算正确,则指向的对象的大小为 0xE0 字节。

要理解这一点,请先编译并运行以下代码(C++,但如果您想使用该语言,我已将 C 行作为注释包括在内):

#include <iostream>                 // #include <stdio.h>
int main() {                        // int main(void) {
    int xyzzy[2];
    int *pXyzzy = &xyzzy[0];
    std::cout << pXyzzy << '\n';    // printf("%p\n", pXyzzy);
    pXyzzy = pXyzzy + 1;
    std::cout << pXyzzy << '\n';    // printf("%p\n", pXyzzy);
    return 0;
}

其输出类似于(添加了我的评论):

0x7fffc9ef1150
0x7fffc9ef1154  // four bytes on

尽管您所做的只是将 one 添加到两个输出之间的地址,但这是四个字节的 clear 差异。

那是因为指针算法是根据你指向的东西的大小缩放的。换句话说,加一不会加一个字节,它会加X 字节,其中 X 是(在本例中)4int.

的大小

在您的调试器会话中发生了完全相同的事情,因为如果编译器和调试器不同意表达式的计算方式,这将令人不安(并且调试起来相当痛苦)。如果您要打印出要添加一个的结构的大小,您会发现它是 0xe0 字节长。

如果你真的想要添加一个字节,你需要告诉编译器把它当作大小为1的东西字节,类似于:

pXyzzy = (int*)((char*)pXyzzy + 1);

这导致:

0x7fffdbd74000
0x7fffdbd74001 // one byte on