Lil*_*aik 1 c infinite-loop while-loop
int main(){
while(1)
{
//code
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是一个无限循环,但这会导致系统崩溃吗?
它的表现如何?
我认为它将耗尽所有堆栈部分。
这是一个无限循环
它是。我注意到,一个不错的现代C编译器会警告您,顺便说一句。
但这是否导致系统崩溃?
不,不会。
如果这是一个用户级进程,则不会导致“系统”(内核)崩溃,因为它不会损坏或滥用内核资源。
您按原样发布的代码也不会导致进程崩溃,因为代码中也没有非法或未定义的东西(它只会做任何有用的事情)。
基本上,这(如果未经优化而编译):
# Instruction
1 main:
2 push rbp ; `int main` function prologue
3 mov rbp, rsp ;
4 .loop:
5 jmp .loop ; Jump to right before this instruction
Run Code Online (Sandbox Code Playgroud)
您可以使用类似于Godbolt.org的编译器输出资源管理器网站来亲自查看此内容:https ://godbolt.org/z/BMzh7i- 注意堆栈指针没有变化(在rsp-忽略mov函数序言中的,即与while循环无关)
这是如何表现的?
它将在汇编代码中编译为一个无级跳转的琐碎无条件分支。(因为操作系统控制抢占式多任务中断定时器处理程序,所以不会导致系统挂起)。
我在想-它会耗尽所有堆栈部分。
这不是因为您发布的代码不会增加堆栈指针(例如,通过在循环内部的堆栈中分配任何内容而不减少堆栈指针,或者通过在循环内部进行函数调用而不弹出被调用函数的框架) - 如果您使用了错误的呼叫约定,则可能会发生这种情况,但这是高级主题)。
如果在while循环中有一个局部变量,则实际上不会导致为每个迭代分配空间,因为以前的迭代值不再可用-因此...
while( 1 ) {
int foo;
int ok = fscanf( fd, "%d", &foo );
if( !ok ) break;
}
Run Code Online (Sandbox Code Playgroud)
...相当于:
int foo;
int ok;
while( 1 ) {
ok = fscanf( fd, "%d", &foo );
if( !ok ) break;
}
Run Code Online (Sandbox Code Playgroud)
(这也是为什么很老的编程语言经常让您在函数开始时声明所有局部变量,而不是允许在函数内部声明的原因-它们不再存在了,因为值得庆幸的是,语言设计人员现在比以前更关心语言人机工程学)。
一般来说,永远不会调用malloc(),而不调用free()(或者更一般地说:从未获取资源而不释放它们),所以此代码将导致你的程序的内存用完了最后:
while( 1 ) {
void* ptr = malloc( 1024 )
}
Run Code Online (Sandbox Code Playgroud)
...但这不会:
while( 1 ) {
void* ptr = malloc( 1024 );
if( ptr ) free( ptr );
}
Run Code Online (Sandbox Code Playgroud)
(嗯,由于堆碎片,它可能会用完内存,具体取决于您的malloc实现情况)
C使得直接操作堆栈变得异常困难(例如,尾调用优化要求编译器将其作为优化来处理:不幸的是,您不能使用C语言功能强制执行尾调用返回)-因此(据我所知),只有两种主要方法可以解决问题:
溢出堆栈的主要方法是推入更多的堆栈帧而不弹出它们-这可以通过进行无限递归的函数调用(无需尾调用优化)来完成。
...或通过做一些愚蠢和/或愚蠢的事情,例如通过使用alloca(例如malloc,但在堆栈上分配内存:但不会告诉您它是否失败)。