2012-01-02 84 views
1

说你做:CPU如何知道任何变量的地址?

void something() 
{ 
    int* number = new int(16); 

    int* sixteen = number; 
} 

怎样的CPU知道我要分配给十六地址?

谢谢

+1

我不知道你想知道什么。但是,可能足以说C代码被转换为机器代码,该代码准确地告诉CPU确切的位置。 – 2012-01-02 22:27:47

+4

你真的在问一个问题的答案是“因为编译器在变量'number'中有地址吗?”。只要确保我理解了这个问题...... – 2012-01-02 22:29:03

+4

你的问题很混乱,因为答案是“对于int int = 5; int five = number;'”的相同方式。除了'number'从哪里获得初始值,这些都是完全相同的。那么,你是在问'new int(16)'从哪里得到一个指针? – 2012-01-02 22:29:33

回答

6

在示例代码中没有什么魔力。就拿这个片段中,例如:

int x = 5; 
int y = x; 

你使用指针的代码是完全一样的 - 电脑并不需要知道任何神奇的信息,它只是复制无论在numbersixteen

至于下方您的评论:

但它是如何知道X或Y是在内存中。如果我要求将x复制到y中,它是如何知道其中哪一个是。

在实践中,大多数机器上,这些天,大概都没有会在内存中,他们将在寄存器中。但是,如果它们在内存中,那么是的,编译器会发出代码来根据需要跟踪所有这些地址。在这种情况下,它们将在堆栈中,所以机器代码将访问堆栈指针寄存器,并用一些编译器决定的偏移量来引用它,这些偏移量指向每个特定变量的存储量。

下面是一个例子。这个简单的功能:

int f(void) 
{ 
    int x = 5; 
    int y = x; 
    return y; 
} 

当铛并没有优化编译,让我在我的机器上输出如下:

_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被保存到xrbp-4,然后该值被复制到yrbp-8

“但是堆栈来自哪里??你可能会问。不过,这个问题的答案是依赖于操作系统和编译器。在您的程序的main函数被调用之前,这一切都已设置完毕,同时您的操作系统需要其他运行时设置。

+0

但它如何知道x或y在内存中的位置。如果我要求将x复制到y中,它是如何知道其中哪一个是。 – jmasterx 2012-01-02 22:38:15

+0

编辑答案以解决您的问题... – 2012-01-02 22:40:14

+0

关于堆栈 - 您可能还会在这里找到更详细的解释:http://altdevblogaday.com/2011/12/14/cc-low-level-curriculum-部分-3-所述堆栈/ – Matt 2012-01-03 02:23:59

3

CPU知道,因为你的程序告诉它。这里的魔力在编译器中。首先,我在Visual Studio中建立这个节目2010年

这是生成(在调试模式)的拆卸:

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) 

调用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 

在这里,你只是确保十六个值是与数字相同的值。所以现在他们指向相同的地址。

} 

您可以通过在局部变量调试窗口中检查他们核实:

+  number 0x00097c58 int * 
+  sixteen 0x00097c58 int * 

你可以做这个实验,并通过拆卸步骤。它通常非常有启发性。