Читаем Linux программирование в примерах полностью

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)

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 /* может быть освобожден */

Перейти на страницу:

Похожие книги

C++ Primer Plus
C++ Primer Plus

C++ Primer Plus is a carefully crafted, complete tutorial on one of the most significant and widely used programming languages today. An accessible and easy-to-use self-study guide, this book is appropriate for both serious students of programming as well as developers already proficient in other languages.The sixth edition of C++ Primer Plus has been updated and expanded to cover the latest developments in C++, including a detailed look at the new C++11 standard.Author and educator Stephen Prata has created an introduction to C++ that is instructive, clear, and insightful. Fundamental programming concepts are explained along with details of the C++ language. Many short, practical examples illustrate just one or two concepts at a time, encouraging readers to master new topics by immediately putting them to use.Review questions and programming exercises at the end of each chapter help readers zero in on the most critical information and digest the most difficult concepts.In C++ Primer Plus, you'll find depth, breadth, and a variety of teaching techniques and tools to enhance your learning:• A new detailed chapter on the changes and additional capabilities introduced in the C++11 standard• Complete, integrated discussion of both basic C language and additional C++ features• Clear guidance about when and why to use a feature• Hands-on learning with concise and simple examples that develop your understanding a concept or two at a time• Hundreds of practical sample programs• Review questions and programming exercises at the end of each chapter to test your understanding• Coverage of generic C++ gives you the greatest possible flexibility• Teaches the ISO standard, including discussions of templates, the Standard Template Library, the string class, exceptions, RTTI, and namespaces

Стивен Прата

Программирование, программы, базы данных