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

на главную - закладки

Жанры

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

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

Шрифт:

16 while (interpret(expression_value) && inrec(iop) == 0)

17 continue;

18 * Теперь развернуто для простоты отладки.

19 */

20 rvall = inrec(iop);

21 if (rvall == 0) {

22 for (;;) {

23 rval2 = rval3 = -1; /* для отладки */

24 rval2 = interpret(expression_value);

25 if (rval2 != 0)

26 rval3 = inrec(iop);

27 if (rval2 == 0 || rval3 != 0)

28 break;

29 }

30 }

31 if (exiting)

32 break;

33 }

34 }

(Номера

строк приведены относительно начала этой процедуры, а не файла.) Эта функция является основой главного цикла обработки
gawk
. Внешний цикл (строки 12 и 33) проходит через файлы данных командной строки. Комментарий в строках 13–19 показывает оригинальный код, который читает из текущего файла каждую запись и обрабатывает ее

Возвращаемое

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

Строки 20–30 представляют переписанный код, который вызывает каждую функцию отдельно, сохраняя возвращаемые значения в локальных переменных, чтобы их можно было напечатать из отладчика. Обратите внимание, как в строке 23 этим переменным каждый раз присваиваются известные, ошибочные значения: в противном случае они могли бы сохранить свои значения от предыдущих итераций цикла. Строка 27 является тестом завершения, поскольку код изменился, превратившись в бесконечный цикл (сравните строку 22 со строкой 16), тест завершения цикла является противоположным первоначальному.

В качестве отступления, мы признаемся, что нам пришлось тщательно изучить переделку, когда мы ее сделали, чтобы убедиться, что она точно соответствует первоначальному коду; она соответствовала. Теперь нам кажется, что, возможно, вот эта версия цикла была бы ближе к оригиналу:

/* Возможная замена для строк 22 - 29 */

do {

 rval2 = rval3 = -1; /* для отладки */

 rval2 = interpret(expression_value);

 if (rval2 != 0)

rval3 = inrec(iop);

} while (rval2 != 0 && rval3 == 0);

Правда в том, что обе версии труднее воспринимать, чем оригинал, и поэтому, возможно, содержат ошибки. Однако, поскольку текущий код работает, мы решили оставить как есть.

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

step
для входа в каждую функцию, а затем использовать
finish
для ее завершения. GDB сообщит вам возвращаемое функцией значение, и с этого места вы можете использовать для продолжения
cont
или
step
. Нам нравится наш подход, поскольку результаты сохраняются в переменных, которые можно проверить (и неоднократно) после вызова функции и даже спустя несколько операторов.

15.4.1.4. Используйте вспомогательные функции отладки

Типичной методикой, применимой во многих случаях, является использование набора значений флагов; когда флаг установлен (т.е. равен true), имеет место определенный факт или применяется определенное условие. Обычно это осуществляется при помощи именованных констант

#define
и битовых операторов С. (Использование битовых флагов и операторы работы с битами мы обсуждали во врезке к разделу 8.3.1 «Стиль POSIX:
statvfs
и
fstatvfs
».)

Например, главная структура данных

gawk
называется
NODE
. У нее большое количество полей, последнее из которых является набором значений флагов. Из файла
awk.h
:

typedef struct exp_node {

 /* ... Куча материала опущена */

 unsigned short flags;

#define MALLOC 1 /* может быть освобожден */

#define TEMP 2 /* должен быть освобожден */

#define PERM 4 /* не может быть освобожден */

#define STRING 8 /* назначен в виде строки */

#define STRCUR 16 /* текущее значение строковое */

#define NUMCUR 32 /* текущее значение числовое */

#define NUMBER 64 /* назначен в виде числа */

#define MAYBE_NUM 128 /* ввод пользователя: если NUMERIC, тогда

* NUMBER */

#define ARRAYMAXED 256 /* размер массива максимальный */

#define FUNC 512 /* параметр представляет имя функции;

* см. awkgram.y */

#define FIELD 1024 /* это является полем */

#define INTLSTR 2048 /* использовать локализованную версию */

} NODE;

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

NODE
для каждого флага использовала отдельное поле
char
, потребовалось бы 12 байтов вместо 2, используемых
unsigned short
. Текущий размер
NODE
(на Intel x86) 32 байта. Добавление лишних 10 байтов увеличило бы ее до 42 байтов. Поскольку
gawk
может потенциально выделять сотни и тысячи (или даже миллионы)
NODE
[170] , сохранение незначительного размера является важным.

170

Серьезно! Часто люди пропускают через

gawk
мегабайты данных. Помните, никаких произвольных ограничений! — Примеч. автора.

Что это должно делать с отладкой? Разве мы не рекомендовали только что использовать для именованных констант

enum
? Ну, в случае объединяемых побитовыми ИЛИ значений
enum
не помогают, поскольку они больше не являются индивидуально распознаваемыми!

Рекомендация: предусмотрите функцию для преобразования флагов в строки. Если у вас есть несколько независимых флагов, установите процедуру общего назначения.

ЗАМЕЧАНИЕ. Необычность этих функций отладки заключается в том, что код приложения никогда их не вызывает. Они существуют лишь для того, чтобы их можно было вызывать из отладчика. Такие функции всегда должны быть откомпилированы с кодом, даже без окружающих

#ifdef
, чтобы их можно было использовать. не предпринимая никаких дополнительных шагов. Увеличение (обычно минимальное) размера кода оправдывается экономией времени разработчика

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

Газлайтер. Том 10

Володин Григорий
10. История Телепата
Фантастика:
боевая фантастика
5.00
рейтинг книги
Газлайтер. Том 10

На границе империй. Том 7. Часть 2

INDIGO
8. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
6.13
рейтинг книги
На границе империй. Том 7. Часть 2

Звездная Кровь. Изгой

Елисеев Алексей Станиславович
1. Звездная Кровь. Изгой
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Звездная Кровь. Изгой

Хозяин Теней 4

Петров Максим Николаевич
4. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Хозяин Теней 4

Картофельное счастье попаданки

Иконникова Ольга
Фантастика:
фэнтези
5.00
рейтинг книги
Картофельное счастье попаданки

Экзорцист: Проклятый металл. Жнец. Мор. Осквернитель

Корнев Павел Николаевич
Фантастика:
фэнтези
героическая фантастика
5.50
рейтинг книги
Экзорцист: Проклятый металл. Жнец. Мор. Осквернитель

Доктора вызывали? или Трудовые будни попаданки

Марей Соня
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Доктора вызывали? или Трудовые будни попаданки

Метатель

Тарасов Ник
1. Метатель
Фантастика:
боевая фантастика
попаданцы
рпг
фэнтези
фантастика: прочее
постапокалипсис
5.00
рейтинг книги
Метатель

Моя на одну ночь

Тоцка Тала
Любовные романы:
современные любовные романы
короткие любовные романы
5.50
рейтинг книги
Моя на одну ночь

Чехов. Книга 2

Гоблин (MeXXanik)
2. Адвокат Чехов
Фантастика:
фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Чехов. Книга 2

Хозяин Теней 2

Петров Максим Николаевич
2. Безбожник
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Хозяин Теней 2

Сумеречный стрелок 7

Карелин Сергей Витальевич
7. Сумеречный стрелок
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Сумеречный стрелок 7

Жизнь под чужим солнцем

Михалкова Елена Ивановна
Детективы:
прочие детективы
9.10
рейтинг книги
Жизнь под чужим солнцем

Красноармеец

Поселягин Владимир Геннадьевич
1. Красноармеец
Фантастика:
боевая фантастика
попаданцы
4.60
рейтинг книги
Красноармеец