2012-01-02 87 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 * 

你可以做這個實驗,並通過拆卸步驟。它通常非常有啓發性。