因此,可以說我有這樣的代碼當你在C中引用靜態變量時究竟發生了什麼?
int my_static_int = 4;
func(&my_static_int);
我傳遞的函數指針my_static_int,效果顯着。但是,編譯代碼時會發生什麼?大道,我認爲:
1)當你宣佈一個非指針變量,C自動創建的指針,並做一些事情像內部的typedef my_static_int爲*(internal_reference)
無論如何,我希望我的問題是足夠描述的
因此,可以說我有這樣的代碼當你在C中引用靜態變量時究竟發生了什麼?
int my_static_int = 4;
func(&my_static_int);
我傳遞的函數指針my_static_int,效果顯着。但是,編譯代碼時會發生什麼?大道,我認爲:
1)當你宣佈一個非指針變量,C自動創建的指針,並做一些事情像內部的typedef my_static_int爲*(internal_reference)
無論如何,我希望我的問題是足夠描述的
如果您確實想知道代碼在外觀下的外觀,您必須讓編譯器生成彙編代碼(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.
因此地址已通過,並用於獲取變量。
指針只是一個術語,可以幫助我們理解正在發生的事情。
&運算符與變量一起使用時,僅表示地址。在運行時不會創建「指針」,只是將變量的地址傳遞給函數。
如果您有:
int x = 3;
int* p = &x;
則將P持有一個內存地址的變量。該內存地址是一個int。
爲什麼不看組裝輸出?您可以使用-S
選項或gcc
或(如果您的系統使用GNU工具鏈)在生成的目標文件或可執行文件上使用objdump -d
命令執行此操作。
編譯代碼時,函數func
接收到您的my_static_int
變量的地址作爲參數。沒有其他的。
當您聲明非指針變量時,不需要創建任何隱式指針。從你的問題中你不清楚你是如何來到這個奇怪的想法。
簡單的回答是,目標代碼會生成一個對符號的引用,其中my_static_int
被分配(通常位於目標模塊的靜態數據段中)。
因此,變量的地址在加載時(當它被分配一個真實的物理地址時)被解析,並且加載程序修正對變量的引用,並用它的地址填充它。