2013-12-20 5 views
2

В настоящее время я работаю над проектом ZigBee WSNDemo, и я застрял в этой части кода. В принципе, я должен использовать этот макрос для целей очереди в функции appInitMsgSender.Использование MACROS для очереди

void appInitMsgSender(void) 
{ 
    txState = APP_MSG_TX_FREE_STATE; 

    resetQueue(&appToSendQueue); 
    resetQueue(&appFreeQueue); 
    resetQueue(&appSentQueue); 
    resetQueue(&appDoneQueue); 

    for (uint8_t i = 0; i < ARRAY_SIZE(appTxBuffers); i++) 
    { 
     putQueueElem(&appFreeQueue, &appTxBuffers[i].next); 
    } 
} 

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

#define DECLARE_QUEUE(queue) QueueDescriptor_t queue = {.head = NULL,} 

// Type of queue element 
typedef struct _QueueElement_t 
{ 
    struct _QueueElement_t *next; 
} QueueElement_t; 

// Queue descriptor 
typedef struct 
{ 
    QueueElement_t *head; 
} QueueDescriptor_t; 

INLINE void resetQueue(QueueDescriptor_t *queue) 
{ 
    queue->head = NULL; 
} 

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

ответ

0

Очередь реализована со структурой данных, известной как linked list. QueueDescriptor_t содержит указатель на первый QueueElement_t в списке. Каждый QueueElement_t содержит указатель на следующий QueueElement_t в списке. Когда указатель QueueDescriptor_t равен NULL, список пуст. Когда указатель QueueElement_t имеет значение NULL, это последний элемент в списке. Связанный список позволяет создавать коллекцию элементов, но элементы не обязательно должны быть смежными в памяти (указатель next ссылается на следующий элемент в коллекции). Для сравнения, массив представляет собой набор элементов, которые являются непрерывными в памяти (нет указателя next).

3

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

Чтобы объявить очередь, будет просто:

DECLARE_QUEUE(appFreeQueue); 

Если мы расширим макрос, это то же самое, как написание:

QueueDescriptor_t appFreeQueue = {.head = NULL,}; 

Если мы затем разверните QueueDescriptor_ttypedef, было бы то же, что и написание:

struct appFreeQueue 
{ 
    QueueElement_t *head = NULL; 
}; 

И если мы расширим QueueElement_ttypedef, мы можем видеть, что каждый элемент указывает на другой элемент того же типа:

struct appFreeQueue 
{ 
    typedef struct _QueueElement_t 
    { 
     struct _QueueElement_t *next = NULL; 
    } *head; 
}; 

Но вместо того, чтобы писать, что каждый раз, когда вы хотите, чтобы объявить очереди, вы можете просто использовать DECLARE_QUEUE макрос вместо этого. Это создаст пустую очередь в виде связанного списка. Связанный список обычно принимает форму каждой ссылки, содержащей две вещи, некоторые данные и указатель на следующую ссылку. Как так:

Element1    Element2    Element3 
[data][*Element2]-> [data][*Element3]-> [data][NULL] 

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

Функция INLINE действует очень похоже на макрос. Где бы вы ни видели resetQueue, в своей голове вы должны заменить его на определенную там функцию.В этом случае он устанавливает указатель самой первой ссылки next на NULL, что приводит к пустой очереди.

Есть небольшие отличия между макросом и функцией INLINE. Эти различия подробно описаны в ответе на этот вопрос: Inline functions vs Preprocessor macros

Смежные вопросы