exponenta event banner

CERT C: PRE32-C правил

Не использовать директивы препроцессора при вызове функциональных макросов

Описание

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

Не используйте директивы препроцессора при вызове функциональных макросов. [1 ]

Внедрение Polyspace

Эта проверка проверяет директиву препроцессора в аргументе макроса.

Примеры

развернуть все

Проблема

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

Например, #ifdef оператор встречается в аргументе для memcpy функция. memcpy функция может быть реализована как макрос.

memcpy(dest, src,
    #ifdef PLATFORM1
      12
    #else
      24
    #endif
  );
Средство проверки помечает подобное использование в printf и assert, которые также могут быть реализованы в виде макросов.

Риск

Во время предварительной обработки функциональный макро-вызов заменяется телом макроса, а параметры заменяются аргументами к макро-вызову (подстановка аргумента). Предположим, макрос min() определяется следующим образом.

#define min(X, Y)  ((X) < (Y) ? (X) : (Y))
При звонке min(1,2), его заменяет кузов ((X) < (Y) ? (X) : (Y)). X и Y заменены на 1 и 2.

Согласно C11 Standard (Sec. 6.10.3), если список аргументов для самого функционально-подобного макроса имеет директивы предварительной обработки, подстановка аргументов во время предварительной обработки не определена.

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

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

Например, для выполнения memcpy с различными аргументами, основанными на #ifdef директива, вызов memcpy несколько раз в пределах #ifdef ветки директивы.

#ifdef PLATFORM1
    memcpy(dest, src, 12);
#else
    memcpy(dest, src, 24);
#endif

Пример - Директивы в функционально-подобных макросах
#include <stdio.h>

#define print(A) printf(#A)

void func(void) {
    print(
#ifdef SW
          "Message 1"
#else
          "Message 2"
#endif
         );
}

В этом примере директивы препроцессора #ifdef и #endif в аргументе к функциональному макросу print().

Исправление - использовать директивы вне макроса

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

#include <stdio.h>

#define print(A) printf(#A)

void func(void) {
#ifdef SW
        print("Message 1");
#else  
        print("Message 2");
#endif 
}

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

Группа: Правило 01. Препроцессор (PRE)
Представлен в R2019a

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

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

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