#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
应该是未定义的,但此程序的结果是{{1} }。
我知道这是一个未定义的程序,但它似乎产生了预期值,为什么?
答案 0 :(得分:2)
正如评论中已经说明的那样,它是未定义的行为 - 因此任何事情都可能发生。
但是,技术上,原因是离开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:
答案 1 :(得分:0)
我没有看到val被破坏,只是改为4.
然后给ptr值4所以4 + 1 = 5
也许我完全错过了一些东西。
答案 2 :(得分:-1)
函数将(* ptr + 1)计算为5,并返回5.此处未定义任何内容。如果您想要未定义的行为,请返回指针,并通过main
中的指针访问内存。
答案 3 :(得分:-1)
如果你检查每个指针的地址,你可以注释不同的地址指针:
#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
==&GT;是未定义的行为,但指针地址之间的差异可以解释为什么变量“i”具有良好的值