Чтение онлайн

ЖАНРЫ

Linux программирование в примерах
Шрифт:

Наконец, можно использовать смешанную методику: условно компилируемый отладочный код для детальной, точной отладки, а постоянно присутствующий код для более грубого вывода.

15.4.2.2. Используйте специальные переменные окружения

Другой полезной уловкой является проверка вашим приложением специальных переменных окружения (документированных или иных). Это может быть особенно полезным для тестирования. Вот другой пример из нашего опыта с

gawk
, но сначала немного основ.

gawk
использует функцию с названием
optimal_bufsize
для получения
оптимального размера буфера для ввода/вывода. Для небольших файлов функция возвращает размер файла. В противном случае, если файловая система определяет размер для использования при вводе/выводе, возвращается это значение (член
st_blksize
структуры
struct stat
, см. раздел 5.4.2 «Получение информации о файле»). Если этот член недоступен,
optimal_bufsize
возвращает константу
BUFSIZ
из
<stdio.h>
. Оригинальная функция (в
posix/gawkmisc.c
) выглядела следующим образом:

1 /* optimal_bufsize --- определяет оптимальный размер буфера */

2

3 int

4 optimal_bufsize(fd, stb) /* int optimal_bufsize(int fd, struct stat *stb); */

5 int fd;

6 struct stat *stb;

7 {

8 /* инициализировать все члены нулями на случай, если ОС не использует их все. */

9 memset(stb, '\0', sizeof(struct stat));

10

11 /*

12 * System V.n, n < 4, не имеет в структуре stat размера

13 * системного блока файла. Поэтому нам нужно сделать разумную

14 * догадку. Мы используем BUFSIZ, поскольку именно это имелось

15 * в виду на первом месте.

16 */

17 #ifdef HAVE_ST_BLKSIZE

18 #define DEFBLKSIZE (stb->st_blksize ? stb->st_blksize : BUFSIZ)

19 #else

20 #define DEFBLKSIZE BUFSIZ

21 #endif

22

23 if (isatty(fd))

24 return BUFSIZ;

25 if (fstat(fd, stb) == -1)

26 fatal("can't stat fd %d (%s)", fd, strerror(errno));

27 if (lseek(fd, (off_t)0, 0) == -1) /* не обычный файл */

28 return DEFBLKSIZE;

29 if (stb->st_size > 0 && stb->st_size < DEFBLKSIZE) /* маленький файл */

30 return stb->st_size;

31 return DEFBLKSIZE;

32 }

Константа

DEFBLKSIZE
является «размером блока по умолчанию»; то есть значением из
struct stat
или
BUFSIZ
. Для терминалов (строка 23) или файлов, которые не являются обычными файлами (
lseek
завершается неудачей, строка 27) возвращаемое значение также равно
BUFSIZ
. Для небольших обычных файлов используется размер
файла. Во всех других случаях возвращается
DEFBLKSIZE
. Знание «оптимального» размера буфера особенно полезно в файловых системах, в которых размер блока больше
BUFSIZ
.

У нас была проблема, когда один из наших контрольных примеров отлично работал на нашей рабочей системе GNU/Linux и на любой другой системе Unix, к которой у нас был доступ. Однако, этот тест последовательно терпел неудачу на других определенных системах.

В течение длительного времени мы не могли получить непосредственный доступ к терпящей неудачу системе, чтобы запустить GDB. В конце концов, мы смогли, однако, ухитриться воспроизвести проблему. Она оказалась связана с размером буфера, который

gawk
использовал для чтения файлов данных: на терпящих неудачи системах размер буфера был больше, чем на нашей системе разработки.

Нам был нужен способ воспроизведения проблемы на своей машине разработки, система с неудачей находилась в стороне за девять часовых поясов, а интерактивный запуск GDB через Атлантический океан мучителен. Мы воспроизвели проблему, заставив

optimal_bufsize
проверять значение специальной переменной окружения
AWKBUFSIZE
. Когда ее значение равно
"exact"
,
optimal_bufsize
всегда возвращает размер файла, каким бы он ни был. Если значением
AWKBUFSIZE
является какое-нибудь целое число, функция возвращает это число. В противном случае, функция возвращается к прежнему алгоритму. Это дает нам возможность запускать тесты, не требуя постоянной перекомпиляции
gawk
. Например,

$ AWKBUFSIZE=42 make check

Это запускает тестовый набор

gawk
с использованием размера буфера в 42 байта. (Тестовый набор проходит.) Вот модифицированная версия
optimal_bufsize
:

1 /* optimal_bufsize --- определение оптимального размера буфера */

2

3 /*

4 * В целях отладки усовершенствуйте это следующим образом:

5 *

6 * Всегда используйте stat для файла, буфер stat используется кодом

7 * более высокого уровня.

8 * if (AWKBUFSIZE == "exact")

9 * return the file size

10 * else if (AWKBUFSIZE == число)

11 * всегда возвращать это число

12 * else

13 * if размер < default_blocksize

14 * return размер

15 * else

16 * return default_blocksize

17 * end if

18 * end if

19 *

20 * Приходится повозиться, чтобы иметь дело с AWKBUFSIZE лишь

21 * однажды, при первом вызове этой процедуры, а не при каждом

22 * ее вызове. Производительность, знаете ли.

23 */

24

25 size_t

Поделиться с друзьями: