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

/* для целей отладки */

struct flagtab {

 int val;          /* Целое значение флага */

 const char *name; /* Строковое имя */

};

Эту структуру можно использовать для представления любого набора флагов с соответствующими строковыми значениями. Каждая отдельная группа флагов имеет соответствующую функцию, которая возвращает печатное представление флагов, которые установлены в настоящее время. Из eval.c:

/* flags2str --- делает значения флагов удобочитаемыми */


const char *flags2str(int flagval) {

 static const struct flagtab values[] = {

  { MALLOC, "MALLOC" },

  { TEMP, "TEMP" },

  { PERM, "PERM" },

  { STRING, "STRING" },

  { STRCUR, "STRCUR" },

  { NUMCUR, "NUMCUR" },

  { NUMBER, "NUMBER" },

  { MAYBE_NUM, "MAYBE_NUM" },

  { ARRAYMAXED, "ARRAYMAXED" },

  { FUNC, "FUNC" },

  { FIELD, "FIELD" },

  { INTLSTR, "INTLSTR" },

  { 0, NULL },

 };


 return genflags2str(flagval, values);

}

flags2str() определяет массив сопоставлений флагов со строками. По соглашению, значение флага 0 означает конец массива. Код вызывает для осуществления работы genflags2str() («общий флаг в строку»). getflags2str() является процедурой общего назначения, которая преобразует значение флага в строку. Из eval.c:

1  /* genflags2str --- общая процедура для преобразования значения флага в строковое представление */

2

3  const char *

4  genflags2str(int flagval, const struct flagtab *tab)

5  {

6   static char buffer(BUFSIZ];

7   char *sp;

8   int i, space_left, space_needed;

9

10  sp = buffer;

11  space_left = BUFSIZ;

12  for (i = 0; tab[i].name != NULL; i++) {

13   if ((flagval & tab[i].val) != 0) {

14    /*

15     * обратите внимание на уловку, нам нужны 1 или 0, чтобы

16     * определить, нужен ли нам символ '|'.

17     */

18    space_needed = (strlen(tab[i].name) + (sp != buffer));

19    if (space_left < space_needed)

20     fatal(_("buffer overflow in genflags2str"));

21

22    if (sp >= buffer) {

23     *sp++ = '|';

24     space_left--;

25    }

26    strcpy(sp, tab[i].name);

27    /* обратите внимание на расположение! */

28    space_left -= strlen(sp);

29    sp += strlen(sp);

30   }

31  }

32

33  return buffer;

34 }

(Номера строк приведены относительно начала функции, а не файла.) Как и в предыдущей версии, идея заключалась в заполнении статического буфера строковыми значениями, такими, как "MALLOC | PERM | STRING | MAYBE_NUM", и возвращении адреса этого буфера. Мы вскоре обсудим причины использования статического буфера; сначала давайте исследуем код.

Указатель sp отслеживает положение следующего пустого слота в буфере, тогда как space_left отслеживает количество оставшегося места; это уберегает нас от переполнения буфера.

Основную часть функции составляет цикл (строка 12), проходящий через массив значений флагов. Когда флаг найден (строка 13), код вычисляет, сколько места требуется строке (строка 18) и проверяет, осталось ли столько места (строки 19–20).

Тест 'sp ! = buffer' для первого значения флага завершается неудачей, возвращая 0. Для последующих флагов тест дает значение 1. Это говорит нам, что между значениями должен быть вставлен разделительный символ '|'. Добавляя результат (1 или 0) к длине строки, мы получаем правильное значение space_needed. Тот же тест с той же целью проводится в строке 22 для проверки строк 23 и 24, которые вставляют символ '|'.

В заключение строки 26–29 копируют значение строки, выверяют количество оставшегося места и обновляют указатель sp. Строка 33 возвращает адрес буфера, который содержит печатное представление строки.

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

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

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

Стивен Прата

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