#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;
}
In the above code, the variable val
in if block is destroyed, so in return (*ptr + 1)
, the value *ptr
should be undefined, but result of this program is 5
.
I know this is a undefined program, but it seems that it produces a expected value, why?
As already stated in the comments, it is undefined behaviour - so anything can happen.
However, technically , the reason is that the stack frame is not changed after leaving the if
block, and that the compiler allocates all required local variables for the whole function at the beginning of the function, instead of creating a new stack frame for each scope. You can see this in the assembly code which is produced by your function:
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
Throughout the whole function, the stack frame layout is
-20(%rbp) => parameter val
-16(%rbp) => ptr
-4(%rbp) => variable val inside the `if` block
Note that nothing prevents the compiler from reusing -4(%rbp)
if you declare a new variable inside another scope at a later point inside your function:
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);
}
If you compare the previous assembly output with the one which is generated with the additional block in place, the only difference are these additional lines:
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:
I don't see val being destroyed, simply changed to 4.
ptr is then given the value of 4
So 4+1 = 5
Maybe I'm missing something completely.
The function evaluates (*ptr + 1) to 5, and returns the 5. Nothing undefined here. If you want undefined behaviour, return the pointer, and access the memory through the pointer in main
.
if you check the address of each pointer you can remark that is not the same address pointer:
#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
==> is undefined behaviour but the difference between address of pointer can explain why the variable "i" have the good value
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.