Категории
Самые читаемые
PochitayKnigi » Компьютеры и Интернет » Интернет » Linux программирование в примерах - Роббинс Арнольд

Linux программирование в примерах - Роббинс Арнольд

Читать онлайн Linux программирование в примерах - Роббинс Арнольд

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 225 226 227 228 229 230 231 232 233 ... 253
Перейти на страницу:

/* ...структуры для других типов операторов... */

typedef enum stmt_type {

 IF, WHILE, FOR, ...

} TYPE; /* Что у нас есть в действительности */

/* Здесь содержатся тип и объединения отдельных видов операторов. */

struct statement {

 TYPE type;

 union stmt {

  struct if_stmt if_st;

  struct while_stmt while_st;

  struct for_stmt for_st;

  ...

 } u;

};

Вместе с объединением удобно использовать макрос, который представляет компоненты объединения, как если бы они были полями структуры. Например:

#define if_s u.if_st /* Так что можно использовать s->if_s вместо s->u.if_st */

#define while_s u.while_st /* И так далее... */

#define for_s u.for_st

...

На только что представленном уровне это кажется разумным и выглядит осуществимым. В действительности, однако, все сложнее, и в реальных компиляторах и интерпретаторах часто есть несколько уровней вложенных структур и объединений. Сюда относится и gawk, в котором определение NODE, значение его флагов и макросов для доступа к компонентам объединения занимают свыше 120 строк![171] Здесь достаточно определений, чтобы дать вам представление о том, что происходит:

typedef struct exp_node {

 union {

  struct {

   union {

    struct exp_node *lptr;

    char *param_name;

    long ll;

   } l;

   union {

    ...

   } r;

   union {

    ...

   } x;

   char *name;

   short number;

   unsigned long reflags;

   ...

  } nodep;

  struct {

   AWKNUM fltnum;

   char *sp;

   size_t slen;

   long sref;

   int idx;

  } val;

  struct {

   struct exp_node *next;

   char *name;

   size_t length;

   struct exp_node *value;

   long ref;

  } hash;

#define hnext sub.hash.next

#define hname sub.hash.name

#define hlength sub.hash.length

#define hvalue sub.hash.value

  ...

 } sub;

 NODETYPE type;

 unsigned short flags;

 ...

} NODE;

#define vname sub.nodep.name

#define exec_count sub.nodep.reflags

#define lnode sub.nodep.l.lptr

#define nextp sub.nodep.l.lptr

#define source_file sub.nodep.name

#define source_line sub.nodep.number

#define param_cnt sub.nodep.number

#define param sub.nodep.l.param_name

#define stptr sub.val.sp

#define stlen sub.val.slen

#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:

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

$1 = {sub = {nodep =

 {1 = {lptr = 0x8095598, param_name = 0x8095598 &quot;xUtb&quot;,

 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},

1 ... 225 226 227 228 229 230 231 232 233 ... 253
Перейти на страницу:
Тут вы можете бесплатно читать книгу Linux программирование в примерах - Роббинс Арнольд.
Комментарии