fflush() 在悬挂指针方面做了什么?
What does fflush() do in terms of dangling pointers?
我发现 this page 说明了创建悬挂点的常见方式。
下面的代码通过返回局部变量的地址来说明悬空指针:
// The pointer pointing to local variable becomes
// dangling when local variable is static.
#include<stdio.h>
int *fun()
{
// x is local variable and goes out of scope
// after an execution of fun() is over.
int x = 5;
return &x;
}
// Driver Code
int main()
{
int *p = fun();
fflush(stdout);
// p points to something which is not valid anymore
printf("%d", *p);
return 0;
}
在 运行 上,这是我收到的编译器警告(如预期的那样):
In function 'fun':
12:2: warning: function returns address of local variable [-Wreturn-local-addr]
return &x;
^
这是我得到的输出(到目前为止还不错):
32743
但是,当我注释掉 fflush(stdout) 行时,这是我得到的输出(具有相同的编译器警告):
5
这种行为的原因是什么? fflush 命令的 presence/absence 究竟是如何导致这种行为变化的?
如您所述,返回指向堆栈上对象的指针是不好的。您只看到 fflush()
调用存在问题的原因是,如果堆栈不存在,则堆栈未被修改。也就是说,5
仍然存在,因此指针解引用仍然将 5
提供给您。如果你在 fun
和 printf
之间调用一个函数(几乎任何函数,可能),它几乎肯定会覆盖那个堆栈位置,使后来的取消引用 return 无论该函数发生什么垃圾留在那里。
这是因为调用 fflush(stdout)
会写入 x
所在的堆栈。
让我解释一下。汇编语言中的堆栈(这是所有编程语言最终以某种方式 运行 的方式)通常用于存储局部变量、return 地址和函数参数。当一个函数被调用时,它会将这些东西压入堆栈:
- 函数完成后继续执行代码的地址。
- 函数的参数,按照使用的调用约定确定的顺序。
- 函数使用的局部变量。
然后将这些东西从堆栈中弹出,一个接一个,只需更改 CPU 认为堆栈顶部的位置即可。这意味着数据仍然存在,但不能保证继续存在。
在 fun()
之后调用另一个函数会覆盖堆栈顶部之前的值,在本例中为 stdout
的值,因此指针的引用值会发生变化。
在不调用另一个函数的情况下,数据会保留在那里,并且在取消引用指针时仍然有效。
我发现 this page 说明了创建悬挂点的常见方式。
下面的代码通过返回局部变量的地址来说明悬空指针:
// The pointer pointing to local variable becomes
// dangling when local variable is static.
#include<stdio.h>
int *fun()
{
// x is local variable and goes out of scope
// after an execution of fun() is over.
int x = 5;
return &x;
}
// Driver Code
int main()
{
int *p = fun();
fflush(stdout);
// p points to something which is not valid anymore
printf("%d", *p);
return 0;
}
在 运行 上,这是我收到的编译器警告(如预期的那样):
In function 'fun':
12:2: warning: function returns address of local variable [-Wreturn-local-addr]
return &x;
^
这是我得到的输出(到目前为止还不错):
32743
但是,当我注释掉 fflush(stdout) 行时,这是我得到的输出(具有相同的编译器警告):
5
这种行为的原因是什么? fflush 命令的 presence/absence 究竟是如何导致这种行为变化的?
如您所述,返回指向堆栈上对象的指针是不好的。您只看到 fflush()
调用存在问题的原因是,如果堆栈不存在,则堆栈未被修改。也就是说,5
仍然存在,因此指针解引用仍然将 5
提供给您。如果你在 fun
和 printf
之间调用一个函数(几乎任何函数,可能),它几乎肯定会覆盖那个堆栈位置,使后来的取消引用 return 无论该函数发生什么垃圾留在那里。
这是因为调用 fflush(stdout)
会写入 x
所在的堆栈。
让我解释一下。汇编语言中的堆栈(这是所有编程语言最终以某种方式 运行 的方式)通常用于存储局部变量、return 地址和函数参数。当一个函数被调用时,它会将这些东西压入堆栈:
- 函数完成后继续执行代码的地址。
- 函数的参数,按照使用的调用约定确定的顺序。
- 函数使用的局部变量。
然后将这些东西从堆栈中弹出,一个接一个,只需更改 CPU 认为堆栈顶部的位置即可。这意味着数据仍然存在,但不能保证继续存在。
在 fun()
之后调用另一个函数会覆盖堆栈顶部之前的值,在本例中为 stdout
的值,因此指针的引用值会发生变化。
在不调用另一个函数的情况下,数据会保留在那里,并且在取消引用指针时仍然有效。