Основы программирования в Linux
Увидеть, как вы добрались до этого места, можно с помощью команды
:backtrace(gdb)<b> backtrace</b>#0 0x0804846f in sort (a=0x804a040, n=5) at debug3.c:23#1 0x08048583 in main() at debug3.c:37(gdb)Это очень простая программа и трассировка у нее короткая, т.к. вы не вызывали много функций из других функций. Вы только видите, что
была вызвана изsortв строке 37 того же файла debug3.c. Обычно проблема гораздо сложнее, и командаmainприменяется для определения маршрута, который привел к месту ошибки. Эта информация очень полезна при отладке функций, вызываемых из множества разных мест.backtraceУ команды
есть сокращенная формаbacktraceи для совместимости с другими отладчиками есть командаbt, выполняющая ту же функцию.whereПросмотр переменных
Отладчик вывел данные в момент остановки программы, и в трассировке стека показаны значения аргументов функции.
Функция
была вызвана с параметромsort, значение которого 0х804а040. Это адрес массива. Обычно он в различных системах разный и зависит от используемых компилятора и операционной системы.аСбойная строка 23 — сравнение одного элемента массива с другим:
/* 23 */ if (a[j].key > a[j+1].key) {Отладчик можно применять для просмотра содержимого параметров функции, локальных переменных и глобальных данных. Команда
отображает содержимое переменных и других выражений:(gdb) <b>print j</b>$1 = 4Вы видите, что у локальной переменной
значениеj. Любые значения, выводимые командами gdb, подобными данной, сохраняются для будущего использования в псевдопеременных. В данном случае переменной4присвоено значение 4, на случай, если она вам позже понадобится. Последующие команды будут сохранять свои результаты в переменных$1,$2и т.д.$3Значение переменной
, равное 4, означает, что программа попыталась выполнить операторjif (а[4].key > а[4+1].key)У массива
, который вы передали функцииarray, только пять элементов, которые пронумерованы от 0 до 4. Поэтому данный оператор считывает несуществующий элемент массиваsort. Переменная циклаarray[5]приняла некорректное значение.jЕсли ваша программа завершилась в строке 25, система обнаружила чтение за пределами массива, только когда взялась за перестановку элементов массива, выполнив оператор
/* 25 */ а[j] = a[j+1];который при
, равной 4, дает в результатеjа[4] = а[4+1];Просмотреть элементы передаваемого массива можно, применив выражение в команде
. В программе gdb вы можете использовать почти любое допустимое выражение языка С для вывода значения переменной, элемента массива или указателя.(gdb) <b>print а[3]</b>$2 = {data = "alex", '\0' <repeats 4091 times>, key = 1}(gdb)Отладчик gdb сохраняет результаты выполнения команд в псевдопеременных вида
. Результат последней команды всегда хранится в псевдопеременной$<<i>номер</i>>, а предыдущей — в$. Это позволяет результат одной команды использовать в другой. Например:$$(gdb) <b>print j</b>$3 = 4(gdb) <b>print a[$-1].key</b>$4 = 1Вывод листинга программы
Вы можете в программе gdb вывести на экран исходный текст программы с помощью команды
. Она выводит фрагмент кода, расположенного рядом с текущей позицией. Последующие вызовыlistвыведут остальной текст. Командеlistможно задать в качестве аргумента имя функции, и команда отобразит фрагмент текста в этом месте программы, или можно указать пару номеров строк, и на экране появится текст программы, находящийся между этими строками.list(gdb) <b>list</b>18 /* 18 */ int s = 1;19 /* 19 */20 /* 20 */ for(; i < n && s != 0; i++) {21 /* 21 */ s = 0;22 /* 22 */ for(j = 0; j < n; j++) {23 /* 23 */ if(a[j].key > a[j+1].key) {24 /* 24 */ item t = a[j];25 /* 25 */ a[j] = a[j+1];26 /* 26 */ a[j+1] = t;27 /* 27 */ s++;(gdb)В строке 22 задано выполнение цикла до тех пор, пока переменная
меньшеj. В данном случаеnравна 5, поэтому уnбудет последнее значение 4, слишком большое. Значение 4 приводит к сравнениюjса[4]и возможной их перестановке. Единственное решение этой конкретной проблемы — исправить условие завершения цикла на следующее:а[5].j < n-1Давайте внесем это изменение, назовем новую программу debug4.c, откомпилируем ее и попробуем снова выполнить.
/* 22 */ for(j = 0; j < n-1; j++) {$ <b>cc -g -o debug4 debug4.с</b>$ <b>./debug4</b>array[0] = {john, 2}array[1] = {alex, 1}array[2] = {bill, 3}array[3] = {neil, 4}array[4] = {rick, 5}Программа все еще не работает, поскольку она вывела неверно отсортированный список. Попробуем применить gdb для пошагового выполнения программы.