簡體   English   中英

if塊中返回一個自動值?

[英]return a auto value in if block?

#include <stdio.h>

static int test(int val)
{
    int *ptr;

    if(val == 0)
    {
        int val = 4;
        ptr = &val;
    }

    return (*ptr + 1);
}

int main(void)
{
    int i = test(0);
    printf("%d\n", i);
    return 0;
}

在上面的代碼中,if塊中的變量val被銷毀,因此在return (*ptr + 1) ,值*ptr應該是未定義的,但是該程序的結果是5

我知道這是一個未定義的程序,但它似乎產生了預期的價值,為什么?

正如評論中已經說明的那樣,它是未定義的行為 - 因此任何事情都可能發生。

但是,從技術上講 ,原因是在離開if塊后堆棧幀沒有改變,並且編譯器在函數開頭為整個函數分配所有必需的局部變量,而不是為每個作用域創建一個新的堆棧幀。 您可以在函數生成的匯編代碼中看到:

ZL4testi:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp          ; set up base pointer for stack frame
                                    ; NOTE: The stack pointer is not modified here
                                    ; since you are not calling any other function
                                    ; from within `test`
        .cfi_def_cfa_register 6
        movl    %edi, -20(%rbp)     ; parameter was passed in %edi, store it in the frame

; if (parameter val == 0)
        cmpl    $0, -20(%rbp)       
        jne     .L2

; Here the scope of the `if` block starts - no changes to the stack frame setup!
; {
;    int val = 4
        movl    $4, -4(%rbp)        ; val is at -4(%rbp)

;    ptr = &val;
        leaq    -4(%rbp), %rax      ; get address of val into %eax
        movq    %rax, -16(%rbp)     ; store address of val into ptr
; }
.L2:
        movq    -16(%rbp), %rax     ; Here, ptr is still containing the address 
                                    ; of val within the stack frame
        movl    (%rax), %eax        ; load `val` from the stack even though it is out of scope
        addl    $1, %eax

        popq    %rbp
        .cfi_def_cfa 7, 8
        ret

在整個功能中,堆棧框架布局是

-20(%rbp)  => parameter val
-16(%rbp)  => ptr
 -4(%rbp)  => variable val inside the `if` block

請注意,如果您在函數內部稍后的位置聲明另一個范圍內的新變量,則不會阻止編譯器重用 -4(%rbp)

static int test(int val) {
    int *ptr;

    if(val == 0) {
        int val = 4;
        ptr = &val;
    }
    if(val == 0) {
        int otherval = 6;
        ptr = &otherval;
    }
    return (*ptr + 1);
}

如果將先前的裝配輸出與使用附加塊生成的裝配輸出進行比較,則唯一的區別是這些附加線:

    cmpl    $0, -20(%rbp)
    jne .L3

    movl    $6, -4(%rbp)      ; here, -4(%rbp) is reused for otherval
    leaq    -4(%rbp), %rax
    movq    %rax, -16(%rbp)
.L3:

我沒有看到val被破壞,只是改為4。

然后ptr的值為4

所以4 + 1 = 5

也許我完全錯過了一些東西。

函數將(* ptr + 1)計算為5,並返回5.此處未定義任何內容。 如果您想要未定義的行為,請返回指針,並通過main的指針訪問內存。

如果你檢查每個指針的地址,你可以注釋不是相同的地址指針:

    #include <stdio.h>

    static int test(int val)
    {
        int *ptr;

        if(val == 0)
        {
            int val = 4;
            ptr = &val;
        }
        printf("ptr @ = %p \n",ptr);
        printf("val @ = %p \n",&val);
        return (*ptr + 1);
    }

int main(void)
{
    int i = test(0);
    printf("%d \n", i);
    return 0;
}  

==> 
    result :
    ptr @ = 0x7fff8b480874 
    val @ = 0x7fff8b48086c 
    5  

==>是未定義的行為,但指針地址之間的差異可以解釋為什么變量“i”具有良好的值

暫無
暫無

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

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