Ниже я вставляю правило из книги по стилю кодирования Майкла Барра.
Я нашел две "ошибки" в предложении: #if ((8 != sizeof(timer_reg_t))
sizeof()
, выполняемую во время компиляции, в инструкции препроцессора, пока я знаю, что это никогда не сработает, действительно, я получил сообщение:ошибка: отсутствует бинарный оператор перед токеном "("
Я что-то пропустил?
Полное правило здесь:
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
sizeof интерпретируется компилятором, а не препроцессором, вы не можете проверить его, как на этапе препроцессора. и, как упоминали другие, вы тоже не сбалансированы
Похоже, C23 static_assert(sizeof(timer_reg_t) == 8, "timer_reg_t struct size incorrect (expected 8 bytes)");
пригодится.
static_assert из c11, почему вы упомянули 23? en.cppreference.com/w/cpp/language/static_assert
@amirhm Нет, _Static_assert
из C11. static_assert
из C23. (Вы смотрите на страницу C++). Вы также можете использовать static_assert
в C11, но через макрос в assert.h
.
Уважаемый, я знаю, что скобки должны быть сбалансированы, я просто копирую и вставляю, как в статье, в любом случае, решая эти вопросы, основная проблема сохраняется.
Вы не можете оценить 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");
Обратите внимание, что вам понадобится #include <assert.h>
для использования static_assert
в C18, в то время как _Static_assert
не требует включения каких-либо заголовков.
%d
— неправильный спецификатор для печати значения типа size_t
. Вместо этого используйте %zu
.
Спасибо, ваш подход хорош, но мне все еще интересно, как такой опытный программист, как Майкл Барр, мог опубликовать это предложение. Мне интересно, есть ли что-то еще, что мне не хватает
Это ошибка, @DanielHSagarra — оплошность, которая показывает, что код, показанный в окончательной версии книги, не был проверен компилятором.
Вы правы по обоим пунктам. Процитированная вами строка из книги 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))
, который не является ни функциональным, ни похожим на фактическое намерение.
Ответы на этот пост, а также ответ Амирма здесь показывают, как можно достичь цели Майкла Барра в этом разделе его книги.
Ваша вторая проблема, связанная с отсутствием ')', также верна. Я бы классифицировал это как незначительную опечатку, которую необходимо исправить, но не имеющую большого значения.
#if (( ())
не сбалансирован.