Ошибка стандарта кодирования Barr C 2018 или недоразумение?

Ниже я вставляю правило из книги по стилю кодирования Майкла Барра.

Я нашел две "ошибки" в предложении: #if ((8 != sizeof(timer_reg_t))

  1. Майкл использует sizeof(), выполняемую во время компиляции, в инструкции препроцессора, пока я знаю, что это никогда не сработает, действительно, я получил сообщение:

ошибка: отсутствует бинарный оператор перед токеном "("

Я что-то пропустил?

  1. Второй вопрос отсутствует')'; Я думаю, что это просто опечатка.

Полное правило здесь:

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

typedef struct
{
uint16_t count; // offset 0
uint16_t max_count; // offset 2
uint16_t _unused; // offset 4
uint16_t enable : 2; // offset 6 bits 15-14
uint16_t b_interrupt : 1; // offset 6 bit 13
uint16_t _unused1 : 7; // offset 6 bits 12-6
uint16_t b_complete : 1; // offset 6 bit 5
uint16_t _unused2 : 4; // offset 6 bits 4-1
uint16_t b_periodic : 1; // offset 6 bit 0
} timer_reg_t;
// Preprocessor check of timer register layout byte count.
#if ((8 != sizeof(timer_reg_t))
# error “timer_reg_t struct size incorrect (expected 8 bytes)”
#endif

🤔 А знаете ли вы, что...
C является популярным языком для системного программирования и написания драйверов устройств.


94
2

Ответы:

Решено

Вы не можете оценить sizeof внутри препроцессора. Он оценивается компилятором. Вы можете просто проверить, как это и должно быть хорошо, как 8.

#include <stdint.h>
#include <stdio.h>

typedef struct
{
uint16_t count; // offset 0
uint16_t max_count; // offset 2
uint16_t _unused; // offset 4
uint16_t enable : 2; // offset 6 bits 15-14
uint16_t b_interrupt : 1; // offset 6 bit 13
uint16_t _unused1 : 7; // offset 6 bits 12-6
uint16_t b_complete : 1; // offset 6 bit 5
uint16_t _unused2 : 4; // offset 6 bits 4-1
uint16_t b_periodic : 1; // offset 6 bit 0
} timer_reg_t;


int main(){
    printf("%d \n", sizeof(timer_reg_t));
    return 0;
} 

Он напечатает 8.

Если вы хотите увидеть проверку времени компиляции, вы также можете использовать static_assert (из <assert.h>):

static_assert(sizeof(timer_reg_t) == 8, "sizeof(timer_reg_t) != 8");

Вы правы по обоим пунктам. Процитированная вами строка из книги Embedded C Coding Standard by Michael Barr] имеет именно те проблемы, которые вы выявили.

Ваша первая забота о строке #if ((8 != sizeof(timer_reg_t)) (сохранение исходной строки, в которой отсутствует закрывающая скобка) является серьезной. Как вы указали, sizeof будет оцениваться во время компиляции, то есть во время предварительной обработки. Мало того, что это значение недоступно, директивы препроцессора уже были обработаны и ушли в то время, когда sizeof может быть присвоено значение. На самом деле, пока ни sizeof, ни timer_reg_t не были #define'd как символические константы, препроцессор будет видеть каждую из них как 0, фактически давая вам #if ((8 != 0(0)), который не является ни функциональным, ни похожим на фактическое намерение.

Ответы на этот пост, а также ответ Амирма здесь показывают, как можно достичь цели Майкла Барра в этом разделе его книги.

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