离开函数后对象仍然可以访问
Object is still reachable after leaving the function
#include <stdio.h>
typedef struct node {
int val;
} node;
node *copy(node *x) {
node *tmp = &((node){.val = 10});
return tmp;
}
int main() {
// node *a = &((node){.val = 9});
node *a = 0;
a = copy(a);
printf("%d\n", a->val);
return 0;
}
据我所知,函数栈中的每个对象在离开函数后都将无法访问。
然而,事实并非如此。
我用 GDB 检查对象在哪里。
(gdb) b 9
(gdb) b 16
(gdb) r
(gdb) p $rsp
= (void *) 0x7fffffffdcc0
(gdb) p $rbp
= (void *) 0x7fffffffdcf0
(gdb) p tmp
= (node *) 0x7fffffffdcdc
(gdb) c
(gdb) p $rsp
= (void *) 0x7fffffffdd00
(gdb) p $rbp
= (void *) 0x7fffffffdd10
(gdb) p a
= (node *) 0x7fffffffdcdc
您可以看到变量 'a' 指向不在 $rsp 和 $rbp 之间的 0x7fffffffdcdc
。
最后程序打印出“10”,没有任何错误信息。
我不明白为什么它可以工作。
当对象超出范围时,您将无法再通过其符号名称访问它。
如果你拿一个指向对象的指针(内存地址)并return它,那么指针指的是对象曾经存在的内存。当对象超出范围时,内存内容不会发生任何特别的变化——它只是可用于其他目的。因此,如果该内存尚未 尚未 被重用,则对象占用的内存未发生变化并不显着。
你正在看一个物体的幻影。它活不了多久。例如,如果您这样做:
printf("%d\n", a->val);
printf("%d\n", a->val);
你会很可能发现在第二次printf()
调用时它已经被修改了,因为printf()
调用已经使用了堆栈space之前在副本中被tmp
占据。
严格来说,这是未定义的行为,任何事情都可能发生。实际上,我所描述的是“典型”——如果你发生了不同的事情,那么耸耸肩,其他事情也是可能的。
#include <stdio.h>
typedef struct node {
int val;
} node;
node *copy(node *x) {
node *tmp = &((node){.val = 10});
return tmp;
}
int main() {
// node *a = &((node){.val = 9});
node *a = 0;
a = copy(a);
printf("%d\n", a->val);
return 0;
}
据我所知,函数栈中的每个对象在离开函数后都将无法访问。 然而,事实并非如此。
我用 GDB 检查对象在哪里。
(gdb) b 9
(gdb) b 16
(gdb) r
(gdb) p $rsp
= (void *) 0x7fffffffdcc0
(gdb) p $rbp
= (void *) 0x7fffffffdcf0
(gdb) p tmp
= (node *) 0x7fffffffdcdc
(gdb) c
(gdb) p $rsp
= (void *) 0x7fffffffdd00
(gdb) p $rbp
= (void *) 0x7fffffffdd10
(gdb) p a
= (node *) 0x7fffffffdcdc
您可以看到变量 'a' 指向不在 $rsp 和 $rbp 之间的 0x7fffffffdcdc
。
最后程序打印出“10”,没有任何错误信息。
我不明白为什么它可以工作。
当对象超出范围时,您将无法再通过其符号名称访问它。
如果你拿一个指向对象的指针(内存地址)并return它,那么指针指的是对象曾经存在的内存。当对象超出范围时,内存内容不会发生任何特别的变化——它只是可用于其他目的。因此,如果该内存尚未 尚未 被重用,则对象占用的内存未发生变化并不显着。
你正在看一个物体的幻影。它活不了多久。例如,如果您这样做:
printf("%d\n", a->val);
printf("%d\n", a->val);
你会很可能发现在第二次printf()
调用时它已经被修改了,因为printf()
调用已经使用了堆栈space之前在副本中被tmp
占据。
严格来说,这是未定义的行为,任何事情都可能发生。实际上,我所描述的是“典型”——如果你发生了不同的事情,那么耸耸肩,其他事情也是可能的。