在基于范围的 for 循环中继续不会重新触发断点?



我正在教一门编程课程,我们将在其中使用C 。我正在整理有关如何使用调试器的讲义,并希望让学生踏上该哈希代码生成器的第一个和姓氏:

int nameHash(string first, string last){
    /* This hashing scheme needs two prime numbers, a large prime and a small
     * prime. These numbers were chosen because their product is less than
     * 2^31 - kLargePrime - 1.
     */
    static const int kLargePrime = 16908799;
    static const int kSmallPrime = 127;
    int hashVal = 0;
    /* Iterate across all the characters in the first name, then the last
     * name, updating the hash at each step.
     */
    for (char ch: first + last) {
        /* Convert the input character to lower case, then make sure it's
         * between 0 and the small prime, inclusive.
         */
        ch = tolower(ch) % (kSmallPrime + 1);
        hashVal = (kSmallPrime * hashVal + ch) % kLargePrime;
    }
    return hashVal;
}

使用GDB,我在包含基于范围的循环的行上设置了一个断点:

(*) for (char ch: first + last)

当我使用GDB运行该程序时,它正如预期的那样,它在此处触发了断点。但是,如果我继续执行,则断点不会重新验证,并且程序运行到完成。

我可以在系统上始终如一地重现这种行为。如果我在循环的主体内设置一个断点并运行直到命中,则如果我在循环顶部添加一个断点,并点击"继续",调试器将跳过循环断点。

我假设这可能是因为基于范围的循环扩展到一系列不同的初始化步骤(我实际上可以看到在我的调试窗口中生成的临时变量),并且断点是在初始化上设置的步骤而不是循环步骤。如果是这样,那是可以理解但令人惊讶的违反直觉的。

我目前的此问题的解决方法是在循环内的第一个语句中,而不是在循环的顶部设置一个断点,但这是违反直觉的,从教学的角度来看,前进的建议非常糟糕。

我的问题如下:

  1. 我的分析正确吗?
  2. 这是我GDB版本的特定于?我在用着
    • ubuntu 16.04和
    • g (Ubuntu 5.4.0-6ubuntu1〜16.04.4)5.4.0 20160609。有
  3. 是否有一种方法可以使GDB将基于循环范围的断点作为循环主体上的断点,而不是初始化步骤?

您期望源代码和执行的一对一映射不存在。在每个循环迭代中,for线并未"重复";它仅介绍并描述了循环的运行方式。

期望for线上的断点只会击中一次。我不记得曾经使用过C,C ,JavaScript,无论奏效的调试器均不同。

将您的断点放在身体的第一行;重复的是身体。

我已经设法使用gdbMSVC2015来重现您的发现。似乎这也适用于常规for(int i=0; ...)循环 - 至少对于我的环境。

我已经搜索了一些网络,对于gdb,我设法在在线文档中找到了信息,该信息指出:

step命令仅在源线的第一个指令中停止。 这样可以防止在交换机中发生的多个停止 语句,循环等

这可能解释了观察到的行为。但是,我找不到是否有一种禁用或覆盖它的方法。

编辑

我已经进行了一些其他检查。看来,当您在循环的最后一个指令之后逐步时,您实际上会返回到for语句。只跳过断点。

在断点部分的文档中,有说明:

断点将在执行任何一项之前停止您的程序 指定位置中的代码。

这只是一个疯狂的猜测,但可能在循环执行期间位置just before CC_9断点无法达到。在循环中,它仅回到条件评估。它已经通过了一些初始化的循环入口点,因此无法在断点处停止。

最新更新