2010-10-06 107 views
2

因此,可以說我有這樣的代碼當你在C中引用靜態變量時究竟發生了什麼?

int my_static_int = 4; 
func(&my_static_int); 

我傳遞的函數指針my_static_int,效果顯着。但是,編譯代碼時會發生什麼?大道,我認爲:

1)當你宣佈一個非指針變量,C自動創建的指針,並做一些事情像內部的typedef my_static_int爲*(internal_reference

無論如何,我希望我的問題是足夠描述的

回答

2

如果您確實想知道代碼在外觀下的外觀,您必須讓編譯器生成彙編代碼(gcc可以使用-S選項執行此操作)。

當你真正把C和指針指向最深層時,你會意識到它只是被傳入的變量的地址而不是變量的值。由於指針直接從代碼移到堆棧(地址可能在鏈接時間或加載時間,而不是運行時間),所以不需要創建額外的內存來存放指針。

由於編譯後的代碼已經知道類型以及如何操作,因此也不需要創建內部類型。

記住,這是實現特定的,考慮下面的代碼:

int my_static_int = 4; 
static void func (int *x) { 
    *x = *x + 7; 
} 
int main (void) { 
    func(&my_static_int); 
    return 0; 
} 

,當與gcc -S編譯得到彙編,生產:

 .file "qq.c" 
.globl _my_static_int 
     .data 
     .align 4 
_my_static_int: 
     .long 4 
     .text 
     .def _func; .scl 3;  .type 32;  .endef 
_func: 
     pushl %ebp 
     movl %esp, %ebp 
     movl 8(%ebp), %eax 
     movl 8(%ebp), %edx 
     movl (%edx), %edx 
     addl $7, %edx 
     movl %edx, (%eax) 
     popl %ebp 
     ret 
     .def ___main;  .scl 2;  .type 32;  .endef 
.globl _main 
     .def _main; .scl 2;  .type 32;  .endef 
_main: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $8, %esp 
     andl $-16, %esp 
     movl $0, %eax 
     addl $15, %eax 
     addl $15, %eax 
     shrl $4, %eax 
     sall $4, %eax 
     movl %eax, -4(%ebp) 
     movl -4(%ebp), %eax 
     call __alloca 
     call ___main 
     movl $_my_static_int, (%esp) 
     call _func 
     movl $0, %eax 
     leave 
     ret 

最重要的一點是這些部分:

movl $_my_static_int, (%esp) ; load address of variable onto stack. 
call _func     ; call the function. 
: 
movl 8(%ebp), %eax ; get passed parameter (the address of the var) into eax 
movl 8(%ebp), %edx ; and also into edx. 
movl (%edx), %edx ; get the value from the address (dereference). 
addl $7, %edx  ; add 7 to it. 
movl %edx, (%eax) ; and put it back into the same address. 

因此地址已通過,並用於獲取變量。

4

指針只是一個術語,可以幫助我們理解正在發生的事情。

&運算符與變量一起使用時,僅表示地址。在運行時不會創建「指針」,只是將變量的地址傳遞給函數。

如果您有:

int x = 3; 
int* p = &x; 

則將P持有一個內存地址的變量。該內存地址是一個int。

0

爲什麼不看組裝輸出?您可以使用-S選項或gcc或(如果您的系統使用GNU工具鏈)在生成的目標文件或可執行文件上使用objdump -d命令執行此操作。

1

編譯代碼時,函數func接收到您的my_static_int變量的地址作爲參數。沒有其他的。

當您聲明非指針變量時,不需要創建任何隱式指針。從你的問題中你不清楚你是如何來到這個奇怪的想法。

0

簡單的回答是,目標代碼會生成一個對符號的引用,其中my_static_int被分配(通常位於目標模塊的靜態數據段中)。

因此,變量的地址在加載時(當它被分配一個真實的物理地址時)被解析,並且加載程序修正對變量的引用,並用它的地址填充它。

相關問題