使用 while 块什么都不做是一件坏事吗?

Is using a while block to do nothing a bad thing?

提问人: 提问时间:1/15/2009 最后编辑:Ian G 更新时间:1/8/2020 访问量:48160

问:

我目前正在学习“C 编程语言”中的摘录。这是我的解决方案之一:

int c;

while ((c=getchar()) != EOF) {

if (c == ' ') {

    while ((c = getchar()) == ' ')

    {}  // do nothing?

    putchar(' ');

}

putchar(c);

}

我在这里找到了一些与我的解决方案完全不同的解决方案,并使用一个额外的变量来跟踪正在发生的事情,而我只是使用 while 循环来跳过所有空格。我的解决方案感觉有点混乱,因为在大括号之间有一个没有任何东西的 while 循环似乎有点黑客。我想知道是否有任何充分的理由不这样做?感谢您的任何建议:-)

c while循环

评论

4赞 Jonathan Leffler 1/15/2009
您需要担心如果内部 while 循环遇到 EOF 会发生什么。目前,您可能将字符 0xFF (y-umlaut) 输出为最后一个字符。如果外环的主体是缩进的,它也会更清晰。

答:

1赞 Dustin 1/15/2009 #1

我不认为程序是,但您的格式很奇怪。这没有错:

/* Eat spaces */
while ((c = getchar()) == ' ');

(也就是说,表示故意没有尸体)

评论

0赞 1/15/2009
啊,我没有意识到我可以这样格式化它,哈哈:)谢谢!
1赞 Al W 1/15/2009
善用评论。我倾向于避免空的 while 循环。一开始它总是看起来像一个错别字,所以我看了两遍才意识到它是故意的,然后再看第三遍以弄清楚它的作用。它们并不是那么可读的 IMO。
0赞 Dustin 1/15/2009
可读性确实是主观的。我总是尽可能地加大括号,所以这在我处理的代码库中对我来说很明显。
53赞 Kyle Cronin 1/15/2009 #2

一点也不 - 我相信你会在 K&R 中找到这样的无所事事的循环,所以这几乎是官方的。

这是个人喜好的问题,但我更喜欢像这样无所事事的循环:

while(something());

其他人则更喜欢将分号放在单独的行上,以强调它是一个循环的事实:

while(something())
  ;

还有一些人更喜欢使用里面什么都没有的括号,就像你所做的那样:

while(something())
{
}

这一切都是有效的 - 你只需要选择你喜欢的风格并坚持下去。

评论

18赞 1/15/2009
我倾向于将“继续”放在一个空循环中:“while (foo) continue;”。我认为,这使得读者更清楚地了解循环的无操作性质,但这是一个非常小的风格问题。
2赞 jmucchiello 1/15/2009
从来没想过。好主意 liw.fi!
2赞 endolith 2/8/2012
在另一个帖子中,有人指出 Google 风格指南官方推荐 or ,因为单独的分号可能看起来像是 do-while 循环的结尾。google-styleguide.googlecode.com/svn/trunk/......{}continue;
0赞 recursive 1/15/2009 #3

我使用过这样的代码。如果情况需要,我认为真的没有任何理由不使用它。

6赞 Chad DeShon 1/15/2009 #4

我认为这是完全可以接受的。

我要么写:

//skip all spaces
while ((c = getchar()) == ' ') {} 

很明显,这行代码只做了一件事。

或者我会这样写:

while ((c = getchar()) == ' ') {
    //no processing required for spaces
}

以便它与代码的其余部分格式匹配。

就个人而言,我不喜欢

while ((c = getchar()) == ' ');

格式。我认为很容易忽略分号。

评论

0赞 Alex Lyman 1/15/2009
+1 我对分号发表了类似的看法,但你的更深入。
1赞 Jim Balter 2/16/2014
没有一个称职的 C 程序员会编写不测试 EOF 的输入循环。
5赞 Cebjyre 1/15/2009 #5

好吧,如果你真的不喜欢空大括号,你可以将这个内部循环重构为

while (c == ' ') {c = getchar();}

不过,这需要额外的比较,所以 do while 循环会更好。

评论

2赞 Tim Post 1/15/2009
更好的可能是: do { c = getchar(); } while (c == ' ');当然,除非 c 在进入循环之前已知 == ' '。
0赞 Nakul Chaudhary 1/15/2009 #6

我认为没有问题。你可以使用它,在许多情况下我更喜欢它。

1赞 Loren Pechtel 1/15/2009 #7

我赞成:

while ((c = getchar()) == ' ') /* Eat spaces */;

众所周知,我还有一个名为 DoNothing 的程序,专门用于在此类情况下调用。它清楚地表明你真的不想做任何事情。

虽然不存在的循环体是完全可以接受的,但应该非常清楚它是故意的。

评论

0赞 Kyle Cronin 1/15/2009
我要做的唯一更改是将分号放在注释之前
6赞 jeffD 1/15/2009 #8

您的问题“使用 while 块什么都不做是一件坏事吗?”也可以从浪费 CPU 周期的角度来回答。在这种情况下,答案是“否”,因为进程将在等待用户输入字符时进入睡眠状态。

只有在输入字符后,该进程才会唤醒。然后测试将发生,如果测试通过,即 c == ' ',该过程将再次进入睡眠状态,直到输入下一个字符。此操作将重复,直到输入非空格字符。

1赞 Charlie Martin 1/15/2009 #9

自古以来使用的规范方式,例如,看看里昂的书——是

while(condition)       // Here's the whole thing
    ;                  // empty body.

事实上,通常,“单独行上的半色”约定用于 null 语句。例如,您偶尔会看到

if( condition-1)
     ;
else if (condition-2)
     stmt;
else {
     // do stuff here
}

这种情况要少得多,但会出现在条件 1 非常复杂的地方,所以你不想否定它并造成混淆,或者代码在其生命周期的一英寸内被手动优化,所以你首先想要最常见的情况。

while(condition) ;

形式是要被奴役地避免的,因为这是一个常见且令人讨厌的错别字:你应该明确表示你是故意这样做的。空括号

 while(condition){
 }

或其变体也很麻烦,因为它们要么不够突出,要么更糟的是导致其他错别字。

-1赞 anon #10

尚未提及的替代选项:

while(condition)
    (void)0;

我真的不喜欢用这种方式写我的循环,但上学期我有一个助教这样做了。

评论

1赞 Jonathan Leffler 1/15/2009
为什么不“继续”作为循环的主体?我更喜欢在一行上单独使用分号,正如大师 K&R 所说明的那样。
0赞 1/15/2009
@Jonathan:这不是我的主意:-)我不会那样写循环。
0赞 thesmart 1/15/2009 #11

嗯,不是真的,但这取决于你的架构。

if (dosomething()) { ; }

上述内容将不断从您的本地堆栈中推送和弹出,这会产生内存开销。此外,您还将使用 noop 操作刷新处理器的管道。

3赞 slim 1/15/2009 #12

一个什么都不做可能是一件坏事:while

while(!ready) {
   /* Wait for some other thread to set ready */
}

...是一种非常非常昂贵的等待方式——只要是假的,它就会使用操作系统给它的 CPU 尽可能多的 CPU,窃取另一个线程可以做有用工作的 CPU 时间。ready

但是,您的循环并非无所事事:

while ((c = getchar()) == ' ')
    {};  // skip

...因为它在调用每一次迭代。因此,正如其他人都同意的那样,你所做的很好。getchar()

评论

0赞 endolith 2/4/2012
什么是不昂贵的阻止方法?
0赞 dwanderson 2/22/2017
如果您需要等待其他线程,那么您需要等待其他线程...没什么可做的了,是吗?
0赞 slim 2/22/2017
@dwanderson 如果需要等待另一个线程,则应使用 和 。Thread.wait()Thread.notify()
0赞 wildplasser 2/23/2017
{};很危险。(谷歌为悬空的别处)我建议。{;}