Читать книгу 📗 "Linux программирование в примерах - Роббинс Арнольд"
Этот код является повторяющимся и склонным к ошибкам, и для
gawk
gawk
awk.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.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
|
space_needed
|
В заключение строки 26–29 копируют значение строки, выверяют количество оставшегося места и обновляют указатель
sp
Теперь несколько слов относительно статического буфера. Обычно хорошая практика программирования не одобряет использование функций, возвращающих адреса статических буферов: множественные вызовы таких функций каждый раз переписывают буфер, вынуждая вызывающего копировать возвращенные данные.
Более того, статический буфер по определению является буфером фиксированного размера. Что случилось с принципом GNU «никаких произвольных ограничений»?
Для ответа на эти вопросы нужно вспомнить, что это отладочная функция. Обычный код никогда не вызывает
getflags2str()