CERT C: Rule MSC38-C

Не обрабатывайте предопределенный идентификатор как объект, если он может быть реализован только как макрос

Описание

Определение правила

Не обрабатывайте предопределенный идентификатор как объект, если он может быть реализован только как макрос.[1]

Реализация Polyspace

Эта проверка проверяет использование предопределенного макроса в качестве объекта.

Примеры

расширить все

Проблема

Предопределенный макрос, используемый в качестве объекта, возникает, когда вы используете определенные идентификаторы таким способом, который требует присутствия базового объекта. Эти идентификаторы определены как макросы. Стандарт C не позволяет вам переопределять их как объекты. Вы используете идентификаторы таким образом, чтобы макро-расширение идентификаторов не могло произойти.

Например, вы ссылаетесь на внешнюю переменную errno:

extern int errno;
Однако errno происходит не как переменная, а как макрос.

Дефект применяется к этим макросам: assert, errno, math_errhandling, setjmp, va_arg, va_copy, va_end, и va_start. Чекер ищет дефект только в исходных файлах (не в файлах заголовков).

Риск

Стандарт C11 (раздел 7.1.4) позволяет вам переопределять большинство макросов как объекты. Чтобы получить доступ к объекту, а не к макросу в исходном файле, вы делаете одно из следующего:

  • Переопределите идентификатор как внешнюю переменную или функцию.

  • Для функциональных макросов заключайте имя идентификатора в круглые скобки.

Если вы пытаетесь использовать эти стратегии для макросов, которые не могут быть переопределены как объекты, возникает ошибка.

Зафиксировать

Не используйте идентификаторы таким образом, чтобы макро-расширение было подавлено.

  • Не пересматривайте идентификаторы как внешние переменные или функции.

  • Для функциональных макросов не заключайте имя макроса в круглые скобки.

Пример - Использование assert as Function
#include<assert.h>
typedef void (*err_handler_func)(int);

extern void demo_handle_err(err_handler_func, int);

void func(int err_code) {
    extern void assert(int);   
    demo_handle_err(&(assert), err_code);
}

В этом примере assert макрос переопределяется как внешняя функция. Когда передан как аргумент к demo_handle_err, идентификатор assert заключено в круглые скобки, что подавляет использование assert макрос.

Коррекция - Использование assert как макрос

Одной из возможных коррекций является непосредственное использование assert макрос из assert.h. Другая реализация функции demo_handle_err непосредственно использует assert макрос вместо взятия адреса assert функция.

#include<assert.h>
void demo_handle_err(int err_code) {
    assert(err_code == 0);                   
}

void func(int err_code) {
    demo_handle_err(err_code);          
}

Проверяйте информацию

Группа: Правило 48. Разное (MSC)
Введенный в R2019a

[1] Это программное обеспечение было создано MathWorks, включающее фрагменты: «Сайт SEI CERT-C», © 2017 Университет Карнеги Меллон, Веб-сайт SEI CERT-C + + © 2017 Университет Карнеги Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОН И/ИЛИ ЕГО ИНЖЕНЕРНОГО ИНСТИТУТА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ НА БАЗИСЕ «КАК ЕСТЬ». УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБОГО ВОПРОСА, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИЮ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ КОММЕРЧЕСКОЙ ВЫГОДЫ, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Это программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллон или его Институтом программной инженерии.