Ошибка стандарта кодирования 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
#if (( ()) не сбалансирован.
tadman 21.02.2023 17:27

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

amirhm 21.02.2023 17:32

Похоже, C23 static_assert(sizeof(timer_reg_t) == 8, "timer_reg_t struct size incorrect (expected 8 bytes)"); пригодится.

Ted Lyngmo 21.02.2023 17:34

static_assert из c11, почему вы упомянули 23? en.cppreference.com/w/cpp/language/static_assert

amirhm 21.02.2023 17:41

@amirhm Нет, _Static_assert из C11. static_assert из C23. (Вы смотрите на страницу C++). Вы также можете использовать static_assert в C11, но через макрос в assert.h.

Ted Lyngmo 21.02.2023 17:43

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

Daniel H Sagarra 21.02.2023 18:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
94
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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");

Обратите внимание, что вам понадобится #include <assert.h> для использования static_assert в C18, в то время как _Static_assert не требует включения каких-либо заголовков.

Ted Lyngmo 21.02.2023 17:46
%d — неправильный спецификатор для печати значения типа size_t. Вместо этого используйте %zu.
Ian Abbott 21.02.2023 18:30

Спасибо, ваш подход хорош, но мне все еще интересно, как такой опытный программист, как Майкл Барр, мог опубликовать это предложение. Мне интересно, есть ли что-то еще, что мне не хватает

Daniel H Sagarra 21.02.2023 18:34

Это ошибка, @DanielHSagarra — оплошность, которая показывает, что код, показанный в окончательной версии книги, не был проверен компилятором.

Jonathan Leffler 21.02.2023 18:46

Вы правы по обоим пунктам. Процитированная вами строка из книги 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)), который не является ни функциональным, ни похожим на фактическое намерение.

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

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

Другие вопросы по теме