Понимание поведения макроса и протопотоков

Заранее спасибо за помощь.

Сначала предисловие. Я смотрел на использование реализации Contiki TSCH, приведенной на https://github.com/contiki-os/contiki/tree/master/core/net/mac/tsch. Выполняя простой пример в симуляторе Cooja (с несколькими сообщениями журнала, которые я добавил в базовый код, чтобы я мог видеть, что происходит), я заметил, что счетчик ASN не увеличивал свой самый значимый байт.

В частности, ASN (абсолютный номер слота для TSCH) задается структурой

// data type of absolute slot number
struct tsch_asn_t {
  uint32_t ls4b; /* least significant 4 bytes */
  uint8_t  ms1b; /* most significant 1 byte */
};

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

// Here is the macro
#define TSCH_ASN_INC(asn, inc) do { \
    printf("TSCH INC1: new UNDEF, old %u, inc %u\n", (asn).ls4b, inc);  \
\
    uint32_t new_ls4b = (asn).ls4b + (inc); \
\
    printf("TSCH INC2: new %u, old %u, inc %u\n",new_ls4b, (asn).ls4b, inc);  \
\
    if(new_ls4b < (asn).ls4b) { (asn).ms1b++; } \
\
    printf("TSCH INC3: new %u, old %u, inc %u\n",new_ls4b, (asn).ls4b, inc);  \
\
    (asn).ls4b = new_ls4b; \
\
    printf("TSCH INC4: new %u, old %u, inc %u\n",new_ls4b, (asn).ls4b, inc);  \
} while(0);

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

Теперь к моему актуальному вопросу. Чтобы определить, почему самый значимый байт не был увеличен, я добавил вышеупомянутые операторы печати в макрос и добавил операторы печати выше и ниже фактического вызова макроса, как показано ниже (обратите внимание, что ASN задается tsch_current_asn, а timeslot_diff - это количество, которое я хочу увеличить ASN на).

printf("TSCH INC BEFORE: ms1b %u, ls4b %u, inc %u\n",tsch_current_asn.ms1b, tsch_current_asn.ls4b, timeslot_diff);
TSCH_ASN_INC(tsch_current_asn, timeslot_diff);
printf("TSCH INC AFTER: ms1b %u, ls4b %u, inc %u\n",tsch_current_asn.ms1b, tsch_current_asn.ls4b, timeslot_diff);

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

// LOG
TIME        DEVID   LOG MSG
00:28.885   ID:1    TSCH INC BEFORE: ms1b 0, ls4b 1877, inc 0
00:28.888   ID:1    TSCH INC1: new UNDEF, old 1877, inc 0
00:28.891   ID:1    TSCH INC2: new 1878, old 0, inc 1877
00:28.895   ID:1    TSCH INC3: new 1878, old 0, inc 1877
00:28.898   ID:1    TSCH INC4: new 1878, old 0, inc 1878
00:28.901   ID:1    TSCH INC AFTER: ms1b 0, ls4b 1878, inc 0

В частности, кажется, что между первым и вторым оператором printf в макросе inc (timeslot_diff) изменилось с 0 на 1877. Другими словами, мне кажется, что оператор

uint32_t new_ls4b = (asn).ls4b + (inc); \

изменил значение inc (timeslot_diff). Более того, мне кажется, что это утверждение меняет ans.ls4b (tsch_current_asn.ls4b) с 1877 на 0.

Есть ли у меня более высокий момент, так сказать, в отношении того, как работают макросы, или это эффект прототоков Contiki (то есть приостановка, а затем возобновление)?

Для справки, фактический код для вызова макроса приведен в строке 1035 https://github.com/contiki-os/contiki/blob/master/core/net/mac/tsch/tsch-slot-operation.c и макрос указан в строке 67 https://github.com/contiki-os/contiki/blob/master/core/net/mac/tsch/tsch-asn.h.

1 ответ

Решение

Похоже, что несоответствие между спецификаторами printf и фактическими типами аргументов происходит в 16-битной архитектуре. Рекомендуется использовать спецификаторы, определенные как макроконстанты формата в inttypes.h для всех целочисленных типов из stdint.h

То есть когда x имеет тип uint32_t вы должны использовать

printf("x is %"PRIu32" \n", x);

вместо

printf("x is %u \n", x);
Другие вопросы по тегам