繁体   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