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

на главную - закладки

Жанры

Linux программирование в примерах

Роббинс Арнольд

Шрифт:

#define stref sub.val.sref

#define stfmt sub.val.idx

#define var_value lnode

...

В

NODE
есть объединение внутри структуры внутри объединения внутри структуры! (Ой.) Поверх всего этого многочисленные «поля» макросов соответствуют одним и тем же компонентам
struct
/
union
в зависимости от того, что на самом деле хранится в
NODE
! (Снова ой.)

Преимуществом такой сложности является то, что код С сравнительно ясный. Нечто вроде '

NF_node->var_value->slen
' читать просто.

У такой гибкости, которую предоставляют объединения, конечно, есть своя

цена. Когда отладчик находится глубоко во внутренностях вашего кода, вы не можете использовать симпатичные макросы, которые имеются в исходном коде. Вы должны использовать развернутое значение. [172] (А для этого придется найти в заголовочном файле соответствующее определение.)

Например, сравните '

NF_node->var_value->slen
' с развернутой формой: '
NF_node->sub.nodep.l.lptr->sub.val.slen
'! Чтобы увидеть значение данных, вы должны набрать последнее в GDB. Взгляните снова на это извлечение из приведенного ранее сеанса отладки GDB:

172

Опять-таки, GCC 3.1 или более новый и GDB 5 дают возможность непосредственного использования макросов, но только лишь если вы используете их совместно, с определенными опциями. Это было описано ранее в разделе 15.4.1.2 «По возможности избегайте макросов с выражениями». — Примеч. автора.

(gdb) print *tree /* Вывести NODE */

$1 = {sub = {nodep =

 {1 = {lptr = 0x8095598, param_name = 0x8095598 "xU\t\b",

 ll = 134829464}, r = {rptr = 0x0, pptr = 0, preg = 0x0,

 hd = 0x0, av = 0x0, r_ent =0), x = {extra = 0x0, xl = 0,

 param_list = 0x0}, name = 0x0, number = 1, reflags = 0},

 val = { fltnum = 6.6614606209589101e-316, sp = 0x0,

 slen = 0, sref = 1, idx = 0),

 hash = {next = 0x8095598, name = 0x0, length = 0,

 value = 0x0, ref = 1}}, type = Node_K_print, flags = 1}

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

($1).sub.val.slen
', чтобы пройти через дерево и перечислить структуры данных.

Есть другие причины для избегания объединений. Прежде всего, объединения не проверяются. Ничто, кроме внимания программиста, не гарантирует, что когда вы получаете доступ к одной части объединения, вы получаете доступ к той части, которая была сохранена последней. Мы видели это в

ch15-union.c
, в котором доступ к обоим «элементам» объединения осуществлялся одновременно.

Вторая причина, связанная с первой, заключается в осторожности с перекрытиями вложенных комбинаций

struct
/
union
. Например, в предыдущей версии
gawk
[173] был такой код.

/* n->lnode перекрывает размер массива, не вызывайте unref, если это массив */

if (n->type != Node_var_array && n->type != Node_array_ref)

unref(n->lnode);

Первоначально

if
не было, был только вызов
unref
, которая освобождает
NODE
, на которую указывает
n->lnode
. Однако, в этот момент
gawk
могла создать аварийную ситуацию. Можете себе представить, сколько времени потребовало отслеживание в отладчике того факта, что то, что рассматривалось как указатель, на самом деле было размером массива!

173

Эта часть кода была с тех пор пересмотрена, поэтому

там больше нет этих строк из примера. — Примеч. автора.

В качестве отступления, объединения значительно менее полезны в С++. Наследование и объектно-ориентированные возможности создают при управлении структурами данных совсем другую ситуацию, которая значительно безопаснее.

Рекомендация: по возможности избегайте объединений (

union
). Если это невозможно, тщательно проектируйте и программируйте их!

15.4.2. Отлаживаемый код времени исполнения

Помимо тех вещей, которые вы добавляете к своему коду для времени компиляции, можно также добавить дополнительный код для обеспечения возможностей отладки времени исполнения. Это особенно полезно для приложений, которые устанавливаются в полевых условиях, когда в системе клиента не будет установленного исходного кода (а может быть, даже и компилятора!)

В данном разделе представлены некоторые методики отладки, которые мы использовали в течение ряда лет, от простых до более сложных. Обратите внимание, что наше рассмотрение ни в коем случае не является исчерпывающим. Это область, в которой стоит иметь некоторое воображение и использовать его!

15.4.2.1. Добавляйте отладочные опции и переменные

Простейшей методикой является наличие опции командной строки, делающих возможным отладку. Такая опция может быть условно откомпилированной для отладки. Однако более гибким подходом является оставить опцию в готовой версии программы. (Вы можете также решить, оставлять или не оставлять эту опцию не документированной. Здесь есть различные компромиссы: ее документирование может дать возможность вашим покупателям или клиентам больше изучить внутренности вашей системы, чего вы можете не хотеть С другой стороны, не документирование ее кажется довольно подлым. Если вы пишете для Open Source или Free Software, лучше документировать опцию.)

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

struct option options[] = {

 ...

 { "debug", required_argument, NULL, 'D' },

 ...

};

int main(int argc, char **argv) {

 int c;

 while ((c = getopt_long(argc, argv, "...D:")) != -1) {

switch (c) {

...

case 'D':

parse_debug(optarg);

break;

...

}

 }

 ...

}

Функция

parse_debug
считывает строку аргументов. Например, это может быть строка разделенных запятыми или пробелами подсистем, вроде "
file,memory,ipc
". Для каждого действительного имени подсистемы функция устанавливает бит в отладочной переменной:

extern int debugging;

void parse_debug(const char *subsystems) {

 char *sp;

 for (sp = subsystems; *sp != '\0';) {

if (strncmp(sp, "file", 4) == 0) {

debugging |= DEBUG_FILE;

sp += 4;

} else if (strncmp(sp, "memory", 6) == 0) {

debugging |= DEBUG_MEM;

sp += 6;

} else if (strncmp(sp, "ipc", 3) == 0) {

Поделиться:
Популярные книги

Моя на одну ночь

Тоцка Тала
Любовные романы:
современные любовные романы
короткие любовные романы
5.50
рейтинг книги
Моя на одну ночь

Черный Маг Императора 8

Герда Александр
8. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 8

Измена. Отбор для предателя

Лаврова Алиса
1. Отбор для предателя
Фантастика:
фэнтези
5.00
рейтинг книги
Измена. Отбор для предателя

Кодекс Крови. Книга II

Борзых М.
2. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга II

Шаг в бездну

Муравьёв Константин Николаевич
3. Перешагнуть пропасть
Фантастика:
фэнтези
космическая фантастика
7.89
рейтинг книги
Шаг в бездну

Часовая битва

Щерба Наталья Васильевна
6. Часодеи
Детские:
детская фантастика
9.38
рейтинг книги
Часовая битва

Вечная Война. Книга II

Винокуров Юрий
2. Вечная война.
Фантастика:
юмористическая фантастика
космическая фантастика
8.37
рейтинг книги
Вечная Война. Книга II

Хроники странного королевства. Вторжение. (Дилогия)

Панкеева Оксана Петровна
110. В одном томе
Фантастика:
фэнтези
9.38
рейтинг книги
Хроники странного королевства. Вторжение. (Дилогия)

Часовой ключ

Щерба Наталья Васильевна
1. Часодеи
Фантастика:
фэнтези
9.36
рейтинг книги
Часовой ключ

Инвестиго, из медика в маги

Рэд Илья
1. Инвестиго
Фантастика:
фэнтези
городское фэнтези
попаданцы
5.00
рейтинг книги
Инвестиго, из медика в маги

Кротовский, может, хватит?

Парсиев Дмитрий
3. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
аниме
7.50
рейтинг книги
Кротовский, может, хватит?

Драконий подарок

Суббота Светлана
1. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
7.30
рейтинг книги
Драконий подарок

Очешуеть! Я - жена дракона?!

Амеличева Елена
Фантастика:
юмористическая фантастика
5.43
рейтинг книги
Очешуеть! Я - жена дракона?!

Идеальный мир для Лекаря 9

Сапфир Олег
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Идеальный мир для Лекаря 9