簡體   English   中英

在C語言中取消引用靜態變量時會發生什么情況?

[英]What exactly happens when you dereference a static variable in C?

所以說我有這個代碼

int my_static_int = 4;
func(&my_static_int);

顯然,我向函數傳遞了指向my_static_int的指針。 但是,編譯代碼時會發生什么? 我考慮過的大道:

1)當您聲明一個非指針變量時,C會自動創建其指針,並在內部做一些類似typedefs my_static_int的*( internal_reference

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

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

&運算符與變量一起使用時,僅表示地址。 在運行時沒有創建“指針”,您只是將變量的地址傳遞給函數。

如果你有:

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

那么p是一個保存內存地址的變量。 在該內存地址內是一個int。

如果您真的想知道代碼的幕后外觀,則必須讓編譯器生成匯編代碼( 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.

因此, 地址被傳遞,並用於獲取變量。

編譯代碼后,函數func接收my_static_int變量的地址作為參數。 沒有其他的。

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

為什么不看匯編輸出? 您可以使用-S選項使用gcc進行此操作,也可以對所得的目標文件或可執行文件使用objdump -d命令(如果您的系統使用GNU工具鏈)。

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

因此,變量的地址在加載時解析(當為其分配了實際的物理地址時),並且加載程序將對變量的引用固定,並用其地址填充。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM