2016-12-27 2 views
3

Я преподаю курс программирования, где мы будем использовать 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 и
    • г ++ (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.4) 5.4.0 20160609. имеют
  3. Есть ли способ, чтобы получить GDB для обрабатывать точку останова в цикле, основанном на диапазоне, как точку останова на теле цикла, а не на этапе инициализации?
+1

«Является ли эта ОС или Qt Creator конкретной версией?» Это может быть причуда GDB, вы можете попробовать это с помощью Visual C++ и/или Clang и посмотреть, получится ли у вас тот же результат. В конце концов, отладчик Qt Creator является графическим интерфейсом. – MrEricSir

+0

@MrEricSir Хороший звонок! Оказывается, это проблема GDB! Я не могу найти ничего об этом с помощью некоторых поисков Google, поэтому я обновил вопрос, чтобы переориентировать его. – templatetypedef

+0

Для отладки производства можно переключиться на вид ассемблера, а затем установить контрольную точку на итерационной части кода. Однако я подозреваю, что «переключиться на вид ассемблера» - это, вероятно, не первая вещь, которую нужно учить! –

ответ

2

Вы ожидаете взаимно однозначного сопоставления исходного кода и выполнения, которое не существует. Строка for не повторяется на каждой итерации цикла; он вводит только и описывает, как будет работать цикл.

Ожидается, что точка останова на линии for будет удалена только один раз. Я не помню, чтобы когда-либо использовал C, C++, JavaScript, какой бы отладчик работал по-другому.

Вместо этого установите точку останова на первой линии кузова; это тело повторяется.

+0

Кстати, хотя приятно видеть C++ 11 в учебном материале, вы можете подумать о принятии этих строк по ссылке const.Конкатенация «первая + последняя» также кажется бесполезной неэффективной; рассмотрим 'for (char ch: boost :: join (first, last))'. –

+0

Я думаю, я удивлен, потому что эквивалентная точка останова в цикле while (?) Запускает точку останова на каждой итерации, отсюда и мое замешательство. Кроме того, вы абсолютно правы, что здесь есть ненужное копирование, но поскольку это первый взгляд на C++, я думаю, что я буду показывать их Boost. :-) – templatetypedef

+0

@templatetypedef: _ «Наверное, я удивлен, потому что эквивалентная точка останова в цикле while (?) Запускает точку останова на каждой итерации». Не правда ли? У меня нет терминала, но это не мое ожидание. –

1

Я сумел воспроизвести вашу прицельно, используя QtCreator с gdb, а также с MSVC2015. Кажется, что это относится и к регулярному циклу for(int i=0; ...) - по крайней мере, для моей среды.

Я искал в Интернете немного и gdb мне удалось найти информацию в online doc которой говорится, что:

Команда шаг останавливается только на первой инструкции исходной строки. Это предотвращает множественные остановки, которые в противном случае могут возникнуть в приборные отчетности, для петель и т.д.

Это могло бы объяснить наблюдаемое поведение. Однако я не смог найти, есть ли способ отключить или перезаписать его.

EDIT

Я сделал некоторые дополнительные проверки. Кажется, что когда вы переходите после последней инструкции в цикле, вы действительно возвращаетесь к оператору for. Пропущена только точка останова.

В документации в breakpoints разделе говорится, что:

Точка останова остановит вашу программу сразу перед выполнением любой из код в указанном месте.

Это просто дикое предположение, но, вероятно, во время выполнения цикла местоположение just before невозможно достичь точки останова. Внутри цикла он возвращается только к оценке состояния. Он уже прошел точку входа цикла, где происходят некоторые инициализации, и поэтому не может остановиться в точке останова.

+0

В регулярном цикле 'for' вы обычно можете устанавливать точки останова в трех местах в одной строке, соответствующие инициализации, условному выходу и приращению (по крайней мере, с использованием отладчика, который я использую больше всего, Visual Studio, когда имеется более одного оператора на строке, столбец, в котором находится ваш курсор, когда вы создаете точку останова, используется для определения того, какой оператор прерывается). –

+0

Это может быть правдой вообще - не спорить с этим. Однако для 'gdb' я использую с QtCreator, устанавливая точку останова, например, для for (int i = 0; i Dusteh

+0

Не важно, на какую часть линии вы создаете точку останова? Точка останова на 'int i = 0' должна останавливаться один раз, но на' i

Смежные вопросы