Макросы препроцессора я не понимаю - PullRequest
1 голос
/ 12 мая 2010

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

typedef int edge_ref;

typedef struct {
    edge_ref next[4];
    void *data[4];
    unsigned mark;
} edge_struct;

#define ROT(e) (((e)&0xfffffffcu)+(((e)+1)&3u))
#define SYM(e) (((e)&0xfffffffcu)+(((e)+2)&3u))
#define TOR(e) (((e)&0xfffffffcu)+(((e)+3)&3u))

#define ONEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[(e)&3]
#define ROTRNEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[((e)+1)&3]
#define SYMDNEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[((e)+2)&3]
#define TORLNEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[((e)+3)&3]

#define MARK(e)  ((edge_struct *)((e)&0xfffffffcu))->mark

и вот как они используются:

edge_ref e;
e = (edge_ref) malloc(sizeof(edge_struct));
ONEXT(e) = e;
SYMDNEXT(e) = SYM(e);
ROTRNEXT(e) = TOR(e);
TORLNEXT(e) = ROT(e);
MARK(e) = 0;
return e;

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

Ответы [ 5 ]

2 голосов
/ 12 мая 2010

Эти макросы являются простой подстановкой кода.Что касается того, что там делают, это другое.

ONEXT(e) = e;

становится ((edge_struct *) ((e) & 0xfffffffcu)) -> next [(e) & 3] = e;

Мне кажется, они загружают структуру с данными, связанными с адресом.

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

1 голос
/ 12 мая 2010

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

((edge_struct *)((e)&0xfffffffcu))

Итак, edge_ref - это указатель на объект типа edge_struct и индекс во внутреннем массиве объекта (бит (e) и 3u).

Файл в: умный, но euurrgghh (наряду с XOR список ).

1 голос
/ 12 мая 2010

Подожди ...

typedef int edge_ref;

#define ONEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[(e)&3]

e = (edge_ref) malloc(sizeof(edge_struct));
ONEXT(e) = e;

Возвращение malloc приводится к подписанному int, которое используется без проверки NULL и маскируется без знака int ...

Я не знаю, для чего этот код, но я настоятельно рекомендую не использовать его для каких-либо целей.

1 голос
/ 12 мая 2010

0xfffffffcu - это просто беззнаковая константа со всеми битами, установленными в 1, кроме последних 2 битов, которые равны 0, т.е. 11111111111111111111111111111100. Он используется в качестве маски для манипулирования двумя нижними битами e. Весь смысл этих макросов заключается в том, что вы можете работать с массивом из 4 структур, который вы рассматриваете как круговой массив (т.е. индексирование по модулю 4).

0 голосов
/ 12 мая 2010

Я предполагаю, что они добавили теги к указателям, предполагая, что они выровнены. (Вот почему есть операции маскирования перед разыменованием).

...