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

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

Жанры

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) {

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

На Берлин!

Дорничев Дмитрий
2. Моё пространственное убежище
Фантастика:
фэнтези
боевая фантастика
рпг
постапокалипсис
5.56
рейтинг книги
На Берлин!

Мастер 7

Чащин Валерий
7. Мастер
Фантастика:
фэнтези
боевая фантастика
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Мастер 7

Последний Герой. Том 2

Дамиров Рафаэль
2. Последний герой
Фантастика:
попаданцы
альтернативная история
4.50
рейтинг книги
Последний Герой. Том 2

Локки 7. Потомок бога

Решетов Евгений Валерьевич
7. Локки
Фантастика:
аниме
эпическая фантастика
фэнтези
5.00
рейтинг книги
Локки 7. Потомок бога

Изгой Проклятого Клана. Том 6

Пламенев Владимир
6. Изгой
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Изгой Проклятого Клана. Том 6

Московское золото и нежная попа комсомолки. Часть Третья

Хренов Алексей
3. Летчик Леха
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Московское золото и нежная попа комсомолки. Часть Третья

Вперед в прошлое 5

Ратманов Денис
5. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 5

Креститель

Прозоров Александр Дмитриевич
6. Ведун
Фантастика:
фэнтези
8.60
рейтинг книги
Креститель

Призыватель нулевого ранга

Дубов Дмитрий
1. Эпоха Гардара
Фантастика:
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Призыватель нулевого ранга

Дитя прибоя

Трофимов Ерофей
Дитя прибоя
Фантастика:
боевая фантастика
попаданцы
фэнтези
5.00
рейтинг книги
Дитя прибоя

Инженер Петра Великого 2

Гросов Виктор
2. Инженер Петра Великого
Фантастика:
попаданцы
альтернативная история
фэнтези
5.00
рейтинг книги
Инженер Петра Великого 2

Камень. Книга 4

Минин Станислав
4. Камень
Фантастика:
боевая фантастика
7.77
рейтинг книги
Камень. Книга 4

Я все еще не царь. Книга XXVI

Дрейк Сириус
26. Дорогой барон!
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Я все еще не царь. Книга XXVI

Кровь на эполетах

Дроздов Анатолий Федорович
3. Штуцер и тесак
Фантастика:
альтернативная история
7.60
рейтинг книги
Кровь на эполетах