【问题标题】:C: Transforming 'while' loops into 'for' loopsC: 将 'while' 循环转换为 'for' 循环
【发布时间】:2013-04-25 23:56:53
【问题描述】:

我们的代码库包含几个while((*assignment*) *condition*) 形式的循环,例如:

while((c = *s++) != '\0') {...}

while((i = getNext()) != NULL) {...}

不幸的是,这些导致编译器发出“条件赋值”警告,我想摆脱它。我的计划是将while 循环转换为for(assignment; condition; assignment) 形式的for 循环,例如:

for(c = *s++; c != '\0'; c = *s++) {...}

for(i = getNext(); i != 0; i = getNext()) {...}

这种转换有效吗?有没有更好的选择?

【问题讨论】:

  • 对于您显示的 while 循环,GCC 不会抱怨“条件分配”。如果您省略了!= '\0'!= NULL 条件 额外级别的括号(例如while (c = *s++)),则GCC 会发出警告。否则,它不会...那么您在哪个平台上使用哪个编译器和哪个选项?
  • 使用#pragma 关闭警告。您正在更改未损坏的代码,因此您冒着引入错误的风险。
  • @Paulpro 您非常困惑并且完全错误。警告是针对while 循环中的原始代码,而不是没有收到警告的转换后的for 循环,即使他们这样做了,您的更改也没有相关性。
  • 你用的是什么编译器?

标签: c for-loop while-loop


【解决方案1】:

转换是有效的,是的,但它们会导致代码更难维护,因为您必须在 两个 处更改分配。

我更倾向于弄清楚如何关闭该特定警告(即使它使用 gcc #pragma warning pragma 之类的东西本地化),因为它毕竟是完全有效的 C 代码,无论是语法还是(在这种情况下)语义上。

【讨论】:

  • +1 表示“更难维护”的评论——这应该管用。这又是 DRY 原则:不要重复自己。扩展违反了 DRY 原则。
  • +1 表示关于关闭警告的第二条评论。如果出现错误,更改未损坏的代码可能会引入错误。
  • (“你你”(低于我的阈值))
【解决方案2】:

就我个人而言,我会这样写第一个循环:

for (char c; (c = *s) != '\0'; ++s)
{
    // ...
}

这清楚地表明s 是正在递增的东西。你也可以省略!= '\0',这是隐式的。

我会将第二个循环保留为while 循环,或者至少保留赋值内部条件。可能是这样,以尽量减少范围污染:

for (iterator i; i = getNext(); )
{
    // ...
}

我个人认为在条件内发生部分循环活动是完全可以接受的;这对于std::cin >> nstd::getline(file, line) 之类的东西也是很自然的。

【讨论】:

  • 不幸的是,这两个建议仍然会导致“分配条件”警告。虽然我同意“在条件内发生部分循环活动是可以接受的”,但这个编译器不同意。
  • @user2121571: 嗯,好吧,迭代器循环可能看起来会有所不同,比如for (iterator it = container.first(); it.has_next(); it = it.next()),或者类似的东西,所以应该只有一个实际的只读条件检查......
  • @user2121571 然后在编译器配置中关闭该警告。如果你不能这样做,那么你的编译器就是一堆低质量的垃圾。
【解决方案3】:

您尚未说明您的编译器是什么,但任何质量的编译器都允许关闭此类警告。但如果你不能做到这一点:

for(;;)
{
    c = *s++;
    if (c == '\0') break;
    ...
}

是等价的并且更通用。同样:

for(;;)
{
    i = getNext();
    if (!i) break;
    ...
}

在很多情况下,比第一个更好(但不等同)是:

for(;; s++)
{
    c = *s;
    if (c == '\0') break;
    ...
}

这些更冗长和丑陋,但它们比你的重复代码的转换要好得多,它是脆弱且容易出错的。

【讨论】:

    【解决方案4】:

    如果我对循环的理解是正确的,那么您的转换是完全有效的,但是这种转换似乎比 while 循环更难阅读。只需在 while 循环之前进行初始化,然后在循环结束时递增以消除警告。

    c = *s++;
    while(c != '\0') 
    {
        ...
        c = *s++;
    }
    

    【讨论】:

    • 这有 OP 转型的所有弊端,还有一些。
    • 嗯,你能解释给我更多的部分吗?
    • 这不等同(想想continue
    猜你喜欢
    • 1970-01-01
    • 2018-02-22
    • 2017-04-26
    • 2018-08-19
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    相关资源
    最近更新 更多