[英]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.