CPU如何知道任意变量的地址?
How does a CPU know the address of any variable?
说你喜欢:
void something()
{
int* number = new int(16);
int* sixteen = number;
}
CPU如何知道我要分配给16的地址?
谢谢
示例代码中没有魔法。以下面的代码片段为例:
int x = 5;
int y = x;
你的指针代码是完全相同的-计算机不需要知道任何神奇的信息,它只是复制number
中的任何内容到sixteen
。
关于你下面的评论:
实际上,在现在的大多数机器上,可能都不在内存中,它们将在寄存器中。但是如果它们在内存中,那么是的,编译器将在必要时发出跟踪所有这些地址的代码。在这种情况下,它们位于堆栈上,因此机器码将访问堆栈指针寄存器,并使用一些编译器决定的偏移量对其解引用,这些偏移量指向每个特定变量的存储。但是它如何知道x或y在内存中的位置。如果我要把x复制到y中,它怎么知道这两个在哪里呢
这里有一个例子。这个简单的函数:
int f(void)
{
int x = 5;
int y = x;
return y;
}
当使用clang编译且未进行优化时,在我的机器上给出以下输出:
_f:
pushq %rbp ; save caller's base pointer
movq %rsp,%rbp ; copy stack pointer into base pointer
movl $5,0xfc(%rbp) ; store constant 5 to stack at rbp-4
movl 0xfc(%rbp),%eax ; copy value at rbp-4 to register eax
movl %eax,0xf8(%rbp) ; copy value from eax to stack at rbp-8
movl 0xf8(%rbp),%eax ; copy value off stack to return value register eax
popq %rbp ; restore caller's base pointer
ret ; return from function
我添加了一些注释来解释生成的每一行代码的作用。重要的是要看到堆栈上有两个变量-一个在0xf8(%rbp)
(或rbp-8
更清楚)和一个在0xfc(%rbp)
(或rbp-4
)。基本算法就像原始代码所显示的那样-常数5
在rbp-4
处被保存到x
中,然后该值在rbp-8
处被复制到y
中。
main
函数之前设置的,与此同时,您的操作系统需要进行其他运行时设置。
CPU知道,因为你的程序告诉它。这里的魔力在于编译器。首先,我在Visual Studio 2010中构建了这个程序。
这是它生成的反汇编(在DEBUG模式下):
void something()
{
003A13C0 push ebp
003A13C1 mov ebp,esp
003A13C3 sub esp,0E8h
003A13C9 push ebx
003A13CA push esi
003A13CB push edi
003A13CC lea edi,[ebp-0E8h]
003A13D2 mov ecx,3Ah
003A13D7 mov eax,0CCCCCCCCh
003A13DC rep stos dword ptr es:[edi]
int* number = new int(16);
003A13DE push 4
003A13E0 call operator new (3A1186h)
在调用operator new之后,EAX = 00097C58
,这是内存管理器决定给我这个程序运行的地址。这是当您取消引用号码时将使用的地址。
003A13E5 add esp,4
003A13E8 mov dword ptr [ebp-0E0h],eax
003A13EE cmp dword ptr [ebp-0E0h],0
003A13F5 je something+51h (3A1411h)
003A13F7 mov eax,dword ptr [ebp-0E0h]
003A13FD mov dword ptr [eax],10h
003A1403 mov ecx,dword ptr [ebp-0E0h]
003A1409 mov dword ptr [ebp-0E8h],ecx
003A140F jmp something+5Bh (3A141Bh)
003A1411 mov dword ptr [ebp-0E8h],0
003A141B mov edx,dword ptr [ebp-0E8h]
003A1421 mov dword ptr [number],edx
int* sixteen = number;
003A1424 mov eax,dword ptr [number]
003A1427 mov dword ptr [sixteen],eax
这里你只是要确保16和number是相同的值。所以现在它们指向同一个地址。
}
您可以通过在Locals调试窗口中检查它们来验证:
+ number 0x00097c58 int *
+ sixteen 0x00097c58 int *
您可以做这个实验并逐步进行拆卸。
相关文章:
- 将数组的地址分配给变量并删除
- 将地址分配给本地指针后,公共对象的变量将消失
- 通过按地址访问变量
- 为什么未命名的结构内联变量在每个翻译单元中没有相同的地址?
- 为什么我可以将变量存储在不是其最小对齐方式的倍数的地址?
- 为什么同一个变量的内存地址不同?
- 从二进制流中读取时,将双精度变量的地址转换为 char* 意味着什么?
- 不同块作用域中的 C++ 变量具有相同的地址
- 循环中的变量被设置为下一个数组的元素始终具有相同的内存地址?
- C++在变量的内存地址上做什么来"deallocate"它?
- 如何在不为其声明变量的情况下获取和使用常量值的地址?
- 如何找到在本地范围内声明的变量的地址?
- 附加调试器并以编程方式获取变量地址 Visual Studio
- 初学者问题:C++指针/地址 - 和变量之后不是以前?
- 为什么我无法获取 MSVS2019 / C++ 中字符或uint8_t变量的内存地址?
- 为什么变量的打印地址在每次执行时都会打印随机值,即使它是 C 中的逻辑地址?
- 变量地址的运算符[]是如何工作的
- 使用基地址和偏移量获取变量的地址
- 两个不同的进程,在同一地址上有 2 个 std::atomic 变量?
- libmysql:警告:返回局部变量"行"的地址(C++/C)