В заключение строки 26–29 копируют значение строки, выверяют количество оставшегося места и обновляют указатель
sp
. Строка 33 возвращает адрес буфера, который содержит печатное представление строки.
Теперь несколько слов относительно статического буфера. Обычно хорошая практика программирования не одобряет использование функций, возвращающих адреса статических буферов: множественные вызовы таких функций каждый раз переписывают буфер, вынуждая вызывающего копировать возвращенные данные.
Более того, статический буфер по определению является буфером фиксированного размера. Что случилось с принципом GNU
«никаких произвольных ограничений»?
Для ответа на эти вопросы нужно вспомнить, что это отладочная функция. Обычный код никогда не вызывает
getflags2str
; она вызывается лишь человеком, использующим отладчик. Ни у одного вызывающего нет указателя на буфер; как разработчику, осуществляющему отладку, нам нет дела до того, что буфер каждый раз переписывается при вызове функции.
На практике фиксированный размер также не является проблемой; мы знаем, что размер
BUFSIZ
достаточен для представления всех флагов, которые мы используем. Тем не менее, поскольку мы опытные и знаем, что вещи могут измениться, в
getflags2str
есть код, предохраняющий себя от переполнения буфера. (Переменная
space_left
и код в строках 18–20.)
В качестве отступления, использование
BUFSIZ
спорно. Эта константа должна использоваться исключительно для буферов ввода/вывода, но часто она используется также для общих строковых буферов. Такой код лучше убрать, определив явные константы, такие, как
FLAGVALSIZE
, и использовав в строке 11 '
sizeof (buffer)
'.
Вот сокращенный сеанс GDB, показывающий использование
flags2str
:
$ gdb gawk /* Запустить GDB с gawk */
GNU gdb 5.3
...
(gdb) break do_print /* Установить контрольную точку */
Breakpoint 1 at 0x805a584: file builtin.c, line 1547.
(gdb) run 'BEGIN { print "hello, world" }' /* Запустить программу */
length = 134830808, value = 0xc, ref = 1}}, type = Node_val, flags = 29}
(gdb) print flags2str(t[i]->flags) /* Вывести значение флага */
$5 = 0x80918a0 "MALLOC|PERM|STRING|STRCUR"
Надеемся, вы согласитесь, что настоящий механизм общего назначения значительно более элегантный и более простой в использовании, чем первоначальный.
Тщательное проектирование и использование массивов структур часто может заменить или слить воедино повторяющийся код.
15.4.1.5. По возможности избегайте объединений
«Не бывает бесплатных обедов»
– Lazarus Long -
union
С относительно эзотерическая возможность. Она помогает экономить память, сохраняя различные элементы в одном и том же физическом пространстве; как программа интерпретирует его, зависит от способа доступа:
/* ch15-union.c --- краткая демонстрация использования union. */
#include <stdio.h>
int main(void) {
union i_f {
int i;
float f;
} u;
u.f = 12.34; /* Присвоить значение с плавающей точкой */
printf("%f also looks like %#x\n", u.f, u.i};
exit(0);
}
Вот что происходит, когда программа запускается на системе Intel x86 GNU/Linux: