while的目的(1); C中的陈述

Abh*_*Rao 54 c while-loop

有什么用途while(1);?我知道while(1)(没有分号)无限循环,类似于自旋锁情况.但是我没看到哪里while(1);可以使用?

示例代码

if(!condition)
{ 
  while(1);
}
Run Code Online (Sandbox Code Playgroud)

注意:这不是do- while()或简单的情况while(1).

dur*_*ill 87

请注意,所有有效的语言陈述都不一定是为了达到目的.它们根据语言的语法有效.人们可以构建许多类似的"无用"语句,例如if (1);.我看到这样的语句是条件(if,while等)和空语句的结合;(虽然它显然没有特定用途,但它也是一个有效的语句).

话虽这么说,我while (1);在安全码中遇到过.当用户使用嵌入式设备执行非常糟糕的操作时,最好阻止他们尝试其他任何操作.有了while (1);,我们可以无条件地阻止设备,直到认可的操作员手动重新启动它.

while(1);也可以是内核恐慌的实现的一部分,虽然for(;;) {}循环似乎是表达无限循环的更常见方式,并且可能存在非空体(例如panic_blink()).

  • 空无限循环的另一个用例是在实现`assert()`时,这当然非常类似于您的安全示例. (5认同)
  • @ user2357112实际上只是要求它真正填补它认为正在填补的利基.这不仅仅是在高度专业化的语言或类似的东西中看到的一些奇怪的功能.这只是实际做你应该做的事情的基本原则,是的,我知道C对于一般来说太好了,它宁愿把你的代码作为一个建议,然后做一些随机的"因为它可以". (4认同)
  • @DavidHammen不是编译器优化应该保持功能相同吗? (3认同)
  • @DavidHammen我说的是非常具体的工具链和非常具体的编译器.这样做的人通常知道他们在做什么,而且他们不会编写可移植的代码. (2认同)
  • @DavidHammen据我了解,C ++编译器可以自由地优化该循环,但C语言编译器则可以。 (2认同)

a.a*_*lam 29

如果你深入到汇编,(从嵌入式系统的角度来看,这更容易掌握,或者如果你试图编写一个bootloader)

你会发现while循环只是一个jmp指令...即

(pseudo code: starting loop address)
add ax, bx
add ax, cx
cmp ax, dx
jz  (pseudo code: another address location)
jmp (pseudo code: starting loop address)
Run Code Online (Sandbox Code Playgroud)

让我们解释一下这是如何工作的,处理器将继续按顺序执行指令......无论如何.所以当它进入这个循环时它会将寄存器bx添加到ax并存储在ax中,将寄存器cx添加到ax并存储到ax,cmp ax,dx(这意味着从ax减去dx)jz指令意味着跳转到(另一个地址)如果零标志置位(如果上述减法的结果为零,则将在标志寄存器中设置一个位),然后jmp到起始循环地址(非常直接)并重做整个事情.

我用这个程序集困扰你的原因是为了告诉你这会在C中翻译成

int A,B,C,D;
// initialize to what ever;

while(true)
{
A = A + B;
A = A + C;

if((A-D)==0)
{break;}

}

// if((X-Y)==0){break;} is the 
// cmp ax, dx
// jz  (pseudo code: another address location)
Run Code Online (Sandbox Code Playgroud)

所以想象一下如果你有一个非常长的指令列表,并且没有以jmp(while循环)结束重复某个部分或加载一个新程序或做某事,那么装配中的senario最终将会到达最后一条指令,然后加载以下指令,找不到任何东西(它会冻结或三重故障或其他东西).

这就是为什么,当你希望程序在事件被触发之前什么也不做的时候,你必须使用while(1)循环,这样处理器就会继续跳到它的位置,而不是到达那个空的指令地址.当事件被触发时,它会跳转到事件处理程序指令地址,执行它,清除中断并返回到while(1)循环,只是跳到它的位置等待进一步的中断.顺便说一句,如果你想要阅读更多关于它的话,那么(1)被称为超级循环...只是对于那些疯狂地渴望在这一点上争论和评论的人来说,这不是装配教程或讲座或任何东西.这只是简单的英语解释,尽可能简单,忽略了许多底层细节,如指针和堆栈等等,并且在某些情况下简化了事情以获得重点.没有人在这里寻找文档的准确性,我知道这个C代码不会像这样编译,但这只适用于Demo !!

  • 所以用简单的英语,它可以让你的程序退出,直到你准备好,即使你的程序没有做任何事情.是? (4认同)

Dav*_*men 18

这是标记C,但我将从C++角度开始.在C++ 11中,编译器可以自由优化while(1);.

从C++ 11标准草案n3092,第6.5节第5段(强调我的):

在for语句的情况下,在for-init语句之外的循环
- 不调用库I/O函数,并且
- 不访问或修改易失性对象,并且
- 不执行同步操作(1.10)或者原子操作(第29条)
可以由实现假定终止.[ 注意:这是为了允许编译器转换,例如删除空循环,即使终止无法证明. - 结束说明]


C11标准有一个类似的条目,但有一个关键的区别.从C11标准草案n1570,(强调我的):

一个迭代语句,其控制表达式不是常量表达式,156)不执行输入/输出操作,不访问易失性对象,并且不在其体内执行同步或原子操作,控制表达式,或(在for的情况下)声明)其表达式-3,可以由实现假定终止.157)
156)省略的控制表达式由非零常量替换,该常量是常量表达式.
157)这是为了允许编译器转换,例如即使在无法证明终止时也删除空循环.


while(1);可以假设 这种方法在C++ 11中终止,但在C11中不终止.即使这样,一些供应商也会将注释157(不绑定)解释为允许它们删除该空循环.while(1);C++ 11和C11 之间的区别在于已定义与未定义的行为.因为循环是空的,所以可以在C++ 11中删除它.在C11中,while(1);可证明是非终止的,这是未定义的行为.由于程序员已经调用了UB,编译器可以自由地做任何事情,包括删除那个有问题的循环.

有关优化编译器删除的一些stackoverflow讨论while(1);.例如,编译器是否允许消除无限循环?,一个用作睡眠的空for循环会被优化掉吗?,优化"while(1);" 在C++ 0x中.请注意,前两个是特定于C的.

  • 同意`while(1);`是非终止的,但为什么有人会称之为"未定义的行为"?它似乎很明确我.它可能是也可能不是_desirable_行为,但是对于编译器来说,优化它是改变程序的含义,因而是坏的. (8认同)
  • @Tibor:Intel,clang和其他人就是这样做的.C11标准中的额外子句("其控制表达式不是常量表达式")似乎允许`while(1);`.但是,C11标准5.1.2.3第4页说"在抽象机器中,所有表达式都按语义指定进行评估.**实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用,那么没有产生所需的副作用**..."因此,C11中仍有一个用于优化`while(1);`远离的编译器供应商. (2认同)

Mah*_*mer 8

我假设它while(1);do循环无关...

while(1);我见过的唯一半有用的实现是一个等待中断的do-nothing循环; 例如,等待SIGCHLD的父进程,表示子进程已终止.在所有子进程终止后,父进程的SIGCHLD处理程序可以终止父线程.

它可以解决问题,但浪费了大量的CPU时间.这种用法可能应该执行某种睡眠以定期放弃处理器.


oua*_*uah 8

嵌入式软件的用法是使用看门狗实现软件复位:

while (1);
Run Code Online (Sandbox Code Playgroud)

或同等但更安全,因为它使意图更清晰:

do { /* nothing, let's the dog bite */ } while (1);
Run Code Online (Sandbox Code Playgroud)

如果看门狗已启用且在x毫秒后未得到确认,我们知道它将重置处理器,因此使用它来实现软件复位.

  • 问题是关于`while(1);`,即没有正文的while循环(注意分号). (5认同)

wal*_*ol1 5

我见过的一个地方while(1);是嵌入式编程.

该体系结构使用主线程来监视事件和工作线程来处理它们.有一个硬件看门狗定时器(这里有解释),它会在一段时间后执行模块的软复位.在主线程轮询循环中,它将重置此计时器.如果主线程检测到不可恢复的错误,while(1);则会使用a来占用主线程,从而触发看门狗复位.我认为断言失败也是通过同样的方式实现的while(1);.