7. неделя

Debugging

Основы работы с утилитой cgdb, отладка программ, массивы, оператор sizeof

Тема лабораторной

На данном занятии вы научитесь отладке своих программ - дебажить с помощью программы cgdb, который собой представляет надстройку над gdb. Умение дебажить программу присуще каждому программисту, оно позволяет облегчить понимание того, как работает программа. Научившись и поняв раз, как работает debugger, вам больше не понадобится писать тестовые выводу на экран типа "я тут".

Цели

  1. Научиться основам cgdb .
  2. Понимать термины и действия, связанные напрямую с процессом отладки программы.
  3. Попрактиковать в работе с массивами чисел.
  4. Ознакомить с оператором sizeof() .

Инструкции

Шаг 1: Linear Search: The Reconstruction

Каждый программист как-то начинал. Разные программисты на начале своего пути учили разные алгоритмы. Посмотрите на следующий фрагмент кода, который пытается осуществить алгоритм линейного поиска. И как это часто бывает - на первый раз чаще всего не выходит.

Вашей задачей на данном этапе будет лишить данную реализацию всех недостатков и показать, почему-таки стоит проходить предмет Основы алгоритмизации и программирования.

Задача 1.1

Скачайте файл linear.c или создайте новый файл, скопировав в него следующий код:

#include <stdio.h>

int search(const int[], const int);

int main(){
    int items[] = { 1, 5, 2, 3, 6, 8, 9, 7 };

    printf("Enter item to find: ");
    int find;
    scanf("%d", &find);

    int position = search(items, find);

    printf("Position of %d is %d\n", find, position);

    return 0;
}

int search(const int items[], const int find){
    int idx = 0;
    while(find != items[idx] || idx < sizeof(items)){
        idx++;
    }

    return idx;
}

Задача 1.2

Скомпилируйте программу так, чтобы её можно было загрузить утилитой cgdb.

При компиляции в таком случае нужно использовать параметр -g, который в конечный бинарный файл добавит информацию, нужную для отладки в родном формате операционной системы (stabs, COFF, XCOFF, или DWARF 2). Эти данные может затем дебаггер gdb считать, таким образом, и cgdb.

Параметр -g можно использовать прямо при сборке следующим образом:

gcc -std=c11 -Wall -Werror -g linear.c -lm -o linear

Таким же образом, можно добавить этот параметр в переменную среды CFLAGS, что позволит использование данного параметра при сборке проекта с помощью make. Поэтому проверьте значение данной переменной в файле ~/.bashrc (или ~/.profile - в зависимости от того, каким образов запускается bash у вас).

В случае, если параметр -g в вашей переменной среды CFLAGS отсутствует, добавьте его (затем перезайдите в систему). При этом можно осуществить и временное изменение переменной CFLAGS, введя следующую команду (изменения будут сброшены при следующем запуске):

export CFLAGS="$CFLAGS -g"

Комментарий

В случае, если вы используете нами предложенный VirtualBox или сервер, параметр -g уже задан в переменной среды CFLAGS.

Задача 1.3

Измените ошибку, связанную с использованием оператора sizeof().

При компиляции программы должна была возникнуть следующая ошибка (при этом есть вероятность, что старые версии компилятора данную ошибку даже не заметят):

linear.c: In function ‘search’:
linear.c:21:45: error: ‘sizeof’ on array function parameter ‘items’ will return size of ‘const int *’ [-Werror=sizeof-array-argument]
     while(find != items[idx] || idx < sizeof(items)){
                                             ^
linear.c:19:22: note: declared here
 int search(const int items[], const int find){
                      ^~~~~
cc1: all warnings being treated as errors

Задача 1.4

С помощью cgdb определите другие ошибки в алгоритме линеарного поиска и исправьте их.

После компиляции программы с параметром -g программу в утилите cgdb запустите командой (linear - название вашего исполнительного файла после компиляции):

cgdb linear

Введение: нажмите ENTER, чтобы продолжить, если вы видите это окно
Рис. 1: Введение: нажмите ENTER, чтобы продолжить, если вы видите это окно

Программа cgdb после запуска
Рис. 2: Программа cgdb после запуска

  • После запуска программы экран делится на две части:
    • Окно с кодом программы (верхняя часть программы)
    • GDB окно (нижняя часть экрана)
  • Утилита ориентирована главным образом на пользователей редактора ViM, так что комбинации некоторых клавиш им будут очень знакомы.
  • Если хотите перенести фокус на окно с кодом, нажмите на клавишу ESC. Так вы также перейдёте в CGDB режим. Если наоборот хотите перевести фокус на GDB окно, нажмите на клавишу i. Так вы также перейдёте в GDB режим.
  • В случае, если вам не подходит размещение окон и, главным образом, их размер, из CGDB режима возможно менять размер окон с помощью клавиш - и =.
  • В режиме CGDB вы можете проходить по коду программы с помощью стрелочек или другими способами, известными вам из VIM.
  • В случае, если на определённой строке вы ходите добавить точку остановки (breakpoint), нажмите SPACE, находясь на нём. Тем же нажатием можно breakpoint убрать.
  • Программу можно запустить из режима CGDB нажатием клавиши F5. В случае, если на какой-то строке будет breakpoint, исполнение программы остановится на соответствующей строке. Начиная с этого момента, программу можно выполнять построчно (строка за строкой), исследуя состояние и значения отдельных переменных.
  • Если ваша программа использует стандартные ввод или вывод, в cgdb нужно включить так называемый TTY режим. Это можно сделать, находясь в CGDB режиме нажатием клавиши T. Таким образом, если вам нужно что-то ввести в программу из клавиатуры, это можно сделать через вид TTY.

TTY окно для работы со стандартными вводом и выводом
Рис. 3: TTY окно для работы со стандартными вводом и выводом

  • Если вы хотите в программе один шаг, нажмите на F8. В любой момент вы можете перейти в окно gdb и выписать значение любой переменной в настоящей области видимости с помощью команды (VARNAME - имя переменной, значение которой вы хотите отследить):
print VARNAME
  • Если вы не хотите постоянно вводить print для изображения переменной, в таком случае можно создать список переменных, которых будут отображаться после каждой остановки программы. Данное действием можно осуществить с помощью (VARNAME - имя переменной, значение которой вы хотите отследить):
display VARNAME
  • Каждой так выписываемой переменной присуждается ID (VARNUMBER), руководствуясь которым можно впоследствии данную переменную из списка для вывода исключить:
undisplay VARNUMBER
  • Если ваша программа остановилась на breakpoint-e и вы бы хотели продолжить её выполнение, можно нажать на F6. Программа таким образом продолжит свою работу, останавливаясь на любом breakpoint-е по пути.
  • Debugger можно запустить в отдельном окне, а в другом окне иметь редактор. После компиляции и новом запуске в cgdb произойдёт обновление. Если вы хотите обновить программу вручную ещё перед её запуском, в режиме GDB напишите программу update.

Список отдельных команд и комбинаций клавиш для cgdb находится в следующей таблице. Для полного списка команд для cgdb перейдите к мануалу к cgdb.

CGDB Mode GDB Mode Description
quit выход и завершение
ESC переход в режим CGDB (окно с кодом программы)
i переход в режим GDB (окно с GDB)
I переход в режим TTY (окно с TTY)
SPACE добавление/удаление breakpoint-а на данной строке
F5 run запуск программы
F6 continue продолжить работу после остановки
F8 next выполнение одного шага в программе
print VARNAME вывод содержания переменной VARNAME
display VARNAME автоматический вывод переменной VARNAME после каждой следующей остановки программы
undisplay VARNUMBER отмена предыдущего действия
update обновить версию запускаемой программы
- уменьшение окна с программным кодом
= увеличение окна с программным кодом
T запуск/выключения TTY вида

Дополнительные источники

  1. CGDB Мануал
  2. Домашняя страница CGDB
  3. Домашняя страница GDB
  4. Linear search
  5. Оператор sizeof(): c-reference - Queries size of the object or type. Used when actual size of the object must be known.
  6. Как определить размер массива

Видео