Читать книгу 📗 "Linux программирование в примерах - Роббинс Арнольд"
Этот код является повторяющимся и склонным к ошибкам, и для
gawkgawkawk.h/* для целей отладки */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()genflags2str()getflags2str()eval.c1 /* genflags2str --- общая процедура для преобразования значения флага в строковое представление */23 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;910 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"));2122 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 }3233 return buffer;34 }(Номера строк приведены относительно начала функции, а не файла.) Как и в предыдущей версии, идея заключалась в заполнении статического буфера строковыми значениями, такими, как "
MALLOC | PERM | STRING | MAYBE_NUMУказатель
spspace_leftОсновную часть функции составляет цикл (строка 12), проходящий через массив значений флагов. Когда флаг найден (строка 13), код вычисляет, сколько места требуется строке (строка 18) и проверяет, осталось ли столько места (строки 19–20).
Тест '
sp ! = buffer|space_needed|В заключение строки 26–29 копируют значение строки, выверяют количество оставшегося места и обновляют указатель
spТеперь несколько слов относительно статического буфера. Обычно хорошая практика программирования не одобряет использование функций, возвращающих адреса статических буферов: множественные вызовы таких функций каждый раз переписывают буфер, вынуждая вызывающего копировать возвращенные данные.
Более того, статический буфер по определению является буфером фиксированного размера. Что случилось с принципом GNU «никаких произвольных ограничений»?
Для ответа на эти вопросы нужно вспомнить, что это отладочная функция. Обычный код никогда не вызывает
getflags2str()