【问题标题】:What's the behavior of this code's loop? [closed]此代码循环的行为是什么? [关闭]
【发布时间】:2017-03-17 11:42:15
【问题描述】:
int main() 
{
    int i;
    int v = 5;
    for (i = 0; v; i++)
    {
        v &= (v - 1);
        printf("%d\n", v);
    }
    return 0;
}

我知道它会在两次迭代后退出,但为什么呢?

【问题讨论】:

  • v什么时候变成false,即0?
  • 添加更多打印并自己解释
  • 调试器也是你的朋友。这里有机会在一个简单的示例中使用它,然后习惯于一直使用它。
  • hint... 5 是二进制的 101,而 4 是二进制的 100。所以 5 & 4(按位与)是 4
  • 我看到你已经击落了几个似乎正确的答案。如果人们没有给你想要的答案,你需要问一个不同的问题。

标签: c assembly arm


【解决方案1】:

循环有一个从零开始的计数器 (i)。它在不满足停止条件的情况下运行其中的行(即,vdifferent than0`)。

在每次迭代中,v 接收vv-1 之间的按位AND (&) 的结果。

然后,v 的值在每次迭代结束时打印出来。

如果您在for (i = 0; v; i++) { 之后添加以下语句,您将能够看到每次迭代中所做的事情:

printf("i=%d, v=%d, v-1=%d, v & (v-1) = %d\n", i, v, v-1, v & (v - 1));

输出:

i=0, v=5, v-1=4, v & (v-1) = 4

4

i=1, v=4, v-1=3, v & (v-1) = 0

0

您可以在线试用here

在第一次迭代中,v = 5 & (5 - 1) = 5 & (4) = 4。从v != 0 开始,循环继续。

在第二次迭代中,v = 4 & (4 - 1) = 4 & (3) = 0。由于v == 0,循环停止。

正如我在我的 cmets 中所说的那样,“正在进行比较,可能是通过 BNZ(如果不为零,则为分支)ASM 指令。如果未设置零标志,则继续; ELSE,分支。您可以找到更详细的信息herehere。"

【讨论】:

  • 嗨,Marcelo,谢谢,但您所解释的内容是为 c-toddler 准备的。我的问题不同。我知道代码会发生什么,否则这将是非常愚蠢的问题,我担心什么因素会使这个 for 循环停止?在预处理器之后,隐式包含在c编译器中的bool文件,例如gcc,当这段代码闪存到一些ARM MCU时,它将如何在运行时结束循环?一些机器操作码是这样做的,还是怎么做的?我没有得到任何理解。
  • 您明确询问“为什么循环在两次迭代后退出”。我回答“因为在第二次迭代中满足停止条件”。这背后没有火箭科学,只是整数之间的比较。如果您需要更多详细信息,请编辑您的问题并提供必要的信息。
  • 正如您所说,“由于 v == 0,循环停止”是的,我的确切问题是“为什么会这样?”,哪个指令集可以做到这一点?或者更准确地说,这是在编译器端还是机器指令集端完成的?谁能解释一下?
  • 嘿,“这背后没有火箭科学,只是整数之间的比较”......没有发生比较。仅监视“v”状态。归零后它会停止循环,所以我需要知道为什么?抱歉问题的开头有误,我可能没有简要解释。
  • @JohnD for 循环控制中三个部分中的第二个,被评估为truefalse。在 C 中,任何非 0 值的计算结果为 true0 的计算结果为 false。所以vtrue,直到它的值是0。表达式v 是显式v != 0 的隐式代码。
【解决方案2】:

您需要查看二进制表示并记住& 是位与运算符:

v = 5 = 101b
// First loop
v = 5 & (5-1) = 5 & 4 = 101b & 100b = 100b = 4
// Second loop
v = 4 & (4-1) = 4 & 3 = 100b & 011b = 000b = 0
// No more loops

【讨论】:

  • 嘿,谢谢,但我知道这一点。 @Marcelo Vinícius 在下面的 cmets 中得到了一些合理的意见
  • 总而言之,v & (v-1) 清除了最低设置位。 wikipedia article for x86's bit-manipulation instruction set 对所有这些都有 C 表达式 + 英文描述,因此它实际上可以作为参考,即使您不关心它如何在 x86 上使用 -mbmi 编译。
  • 哦,太好了..谢谢彼得。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-26
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
相关资源
最近更新 更多