Чтение онлайн

на главную

Жанры

Linux программирование в примерах

Роббинс Арнольд

Шрифт:

Вот сокращенный пример из

io.c
в дистрибутиве
gawk
:

void set_RS {

 ...

 RS_is_null = FALSE;

 if (RS->stlen == 0) {

...

RS_is_null = TRUE;

...

matchrec = rsnullscan;

 }

}

После

установки и сохранения
RS_is_null
ее можно протестировать в коде и вывести из-под отладчика.

ЗАМЕЧАНИЕ. Начиная с GCC 3.1 и версии 5 GDB, если вы компилируете свою программу с опциями

– gdwarf-2
и
– g3
, вы можете использовать макросы из-под GDB. В руководстве по GDB утверждается, что разработчики GDB надеются найти в конце концов более компактное представление для макросов, и что опция
– g3
будет отнесена к группе
– g
.

Однако, использовать макросы таким способам позволяет лишь комбинация GCC, GDB и специальных опций: если вы не используете GCC (или если вы используете более старую версию), у вас все еще есть проблема. Мы придерживаемся своей рекомендации избегать по возможности таких макросов.

Проблема с макросами распространяется также и на фрагменты кода. Если макрос определяет несколько операторов, вы не можете установить контрольную точку в середине макроса. Это верно также для inline-функций C99 и С++: если компилятор заменяет тело inline-функции сгенерированным кодом, снова невозможно или трудно установить внутри него контрольную точку. Это имеет связь с нашим советом компилировать лишь с одной опцией

– g
; в этом случае компиляторы обычно не используют inline-функции.

Обычно с такими строками используется переменная, представляющая определенное состояние. Довольно просто, и это рекомендуется многими книгами по программированию на С, определять с помощью

#define
для таких состояний именованные константы. Например:

/* Различные состояния, в которых можно

находиться при поиске конца записи. */

#define NOSTATE 1 /* сканирование еще не началось (все) */

#define INLEADER 2 /* пропуск начальных данных (RS = "") */

#define INDATA 3 /* в теле записи (все) */

#define INTERM 4 /* терминатор сканирования (RS = RS = regexp) */

int state;

...

state = NOSTATE;

...

state = INLEADER;

...

if (state != INTERM) ...

На уровне исходного кода это выглядит замечательно. Но опять-таки, есть проблема, когда вы пытаетесь просмотреть код из GDB:

(gdb) print state

$1 = 2

Здесь вы также вынуждены возвращаться обратно и смотреть в заголовочный файл, чтобы выяснить, что означает 2. Какова же альтернатива?

Рекомендация: Для определения именованных констант используйте вместо макросов перечисления (enum). Использование исходного кода такое же, а значения enum может выводить также и отладчик.

Пример, тоже из

io.c
в
gawk
:

typedef enum scanstate {

 NOSTATE, /* сканирование еще не начато (все) */

 INLEADER, /* пропуск начальных данных (RS = "") */

 INDATA, /* в теле записи (все) */

 INTERM, /* терминатор сканирования (RS = "", RS = regexp) */

} SCANSTATE;

SCANSTATE state;

/* ... остальной код без изменений! ... */

Теперь при просмотре state из GDB мы видим что-то полезное:

(gdb) print state

$1 = NOSTATE

15.4.1.3. При необходимости переставляйте код

Довольно часто условие в

if
или
while
состоит из нескольких проверок, разделенных
&&
или
||
. Если эти проверки являются вызовами функций (или даже не являются ими), невозможно осуществить пошаговое прохождение каждой отдельной части условия. Команды GDB
step
и
next
работают на основе операторов (statements), а не выражений (expressions). (Разнесение их по нескольким строкам все равно не помогает).

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

Вот конкретный пример: функция

do_input
из файла
io.c gawk
:

1 /* do_input --- главный цикл обработки ввода */

2

3 void

4 do_input

5 {

6 IOBUF *iop;

7 extern int exiting;

8 int rval1, rval2, rval3;

9

10 (void)setjmp(filebuf); /* for 'nextfile' */

11

12 while ((iop = nextfile(FALSE)) != NULL) {

13 /*

14 * Здесь было:

15 if (inrec(iop) == 0)

Поделиться:
Популярные книги

Око василиска

Кас Маркус
2. Артефактор
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Око василиска

Ученичество. Книга 1

Понарошку Евгений
1. Государственный маг
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Ученичество. Книга 1

Кодекс Охотника. Книга XXV

Винокуров Юрий
25. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
6.25
рейтинг книги
Кодекс Охотника. Книга XXV

Кодекс Охотника. Книга IV

Винокуров Юрий
4. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга IV

Жребий некроманта 3

Решетов Евгений Валерьевич
3. Жребий некроманта
Фантастика:
боевая фантастика
5.56
рейтинг книги
Жребий некроманта 3

Идеальный мир для Лекаря 11

Сапфир Олег
11. Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 11

Хочу тебя навсегда

Джокер Ольга
2. Люби меня
Любовные романы:
современные любовные романы
5.25
рейтинг книги
Хочу тебя навсегда

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

Барон диктует правила

Ренгач Евгений
4. Закон сильного
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Барон диктует правила

Мимик нового Мира 8

Северный Лис
7. Мимик!
Фантастика:
юмористическая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Мимик нового Мира 8

Расческа для лысого

Зайцева Мария
Любовные романы:
современные любовные романы
эро литература
8.52
рейтинг книги
Расческа для лысого

Ох уж этот Мин Джин Хо 2

Кронос Александр
2. Мин Джин Хо
Фантастика:
попаданцы
5.00
рейтинг книги
Ох уж этот Мин Джин Хо 2

Заход. Солнцев. Книга XII

Скабер Артемий
12. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Заход. Солнцев. Книга XII

Барон не играет по правилам

Ренгач Евгений
1. Закон сильного
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Барон не играет по правилам