Ошибка стандарта кодирования 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
Руководство для начинающих по веб-разработке на React.js
Руководство для начинающих по веб-разработке на React.js
Веб-разработка - это захватывающая и постоянно меняющаяся область, которая постоянно развивается благодаря новым технологиям и тенденциям. Одним из...
Разница между Angular и React
Разница между Angular и React
React и AngularJS - это два самых популярных фреймворка для веб-разработки. Оба фреймворка имеют свои уникальные особенности и преимущества, которые...
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
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)), который не является ни функциональным, ни похожим на фактическое намерение.

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

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

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