Понимание поведения макроса и протопотоков
Заранее спасибо за помощь.
Сначала предисловие. Я смотрел на использование реализации 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);