Reputation: 372992
I'm teaching a programming course where we'll be using C++. I was putting together a handout about how to use the debugger and wanted to have students step through the execution of this hash code generator for first and last names:
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;
}
Using gdb, I set a breakpoint on the line containing the range-based for loop:
(*) for (char ch: first + last)
When I ran the program with gdb and as expected it triggered a breakpoint here. However, if I then continue execution, the breakpoint does not retrigger and the program runs to completion.
I can reproduce this behavior consistently on my system. If I set a breakpoint inside the body of the loop and run until it's hit, if I then add a breakpoint at the top of the loop and hit "continue" the debugger will skip over the loop breakpoint.
I assume that this is probably because a range-based for loop expands out into a series of different initialization steps (I can actually see the temporary variables that were generated in my debug window) and the breakpoint is getting set on the initialization step rather than the loop step. If that's the case, it's understandable but surprisingly counterintuitive.
My current workaround for this issue is to set a breakpoint at the first statement inside the loop rather than at the top of the loop, but this is counterintuitive and, from a pedagogical perspective, really bad advice going forward.
My questions are the following:
Upvotes: 3
Views: 960
Reputation: 1536
I've managed to reproduce your sighting using QtCreator
with gdb
as well as with MSVC2015
. Seems that this applies also to the regular for(int i=0; ...)
loop - at least for my environment.
I've searched the web a bit and for gdb
I managed to find the information in the online doc which states that:
The step command only stops at the first instruction of a source line. This prevents the multiple stops that could otherwise occur in switch statements, for loops, etc.
This might explain the observed behaviour. However I wasn't able to find if there is a way to disable or overwrite it.
EDIT
I've done some additional checking. It seems that when you step after last instruction in loop you actually go back to the for
statement. Only the breakpoint is skipped.
In the docs in breakpoints section it is stated that:
The breakpoint will stop your program just before it executes any of the code in the specified location.
This is just a wild guess but probably during the loop execution the location just before
the breakpoint isn't reachable. Within the loop it goes only back to the condition evaluation. It has already passed the loop entry-point where some initializations occur and therefore cannot stop at breakpoint.
Upvotes: 1
Reputation: 385274
You're expecting a one-to-one mapping of source code and execution that doesn't quite exist. The for
line isn't "repeated" on each loop iteration; it only introduces and describes how the loop will operate.
It is expected behaviour that a breakpoint on the for
line will only be hit once. I don't recall ever using a C, C++, JavaScript, whatever debugger that worked differently.
Put your breakpoint on the first line of the body, instead; it is the body that is repeated.
Upvotes: 2