Inline constraint not respected

Изменяемая статическая переменная изменена в нестатической встроенной функции

Описание

Этот дефект возникает, когда вы ссылаетесь на статическую переменную изменяемой области файла или задаете локальную изменяемую статическую переменную в нестатической встроенной функции. Проверка рассматривает переменную как изменяемую, если она не const-квалифицированный.

Для образца, var является изменяемым static переменная, заданная в inline функциональные func. g_step является файл статической переменной видоизменяемой области видимости, упомянутой в той же inlined функции.

static int g_step;
inline void func (void) {
   static int var = 0;
   var += g_step;
}

Риск

При изменении статической переменной при нескольких вызовах функций ожидается изменение одной и той же переменной при каждом вызове. Например, каждый раз, когда вы звоните func, тот же образец var1 приращение, но отдельный образец var2 приращение.

void func(void) {
   static var1 = 0;
   var2 = 0;
   var1++;
   var2++;
}

Если функция имеет inlined и non-inlined определение (в отдельных файлах), при вызове функции стандарт C позволяет компиляторам использовать inlined или non-inlined форму (см. ISO®/ IEC 9899:2011, с. 6.7.4). Если ваш компилятор использует встроенное определение в одном вызове, а не встроенное определение в другом, вы больше не изменяете одну и ту же переменную в обоих вызовах. Это поведение бросает вызов ожиданиям от статической переменной.

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

Используйте одно из следующих исправлений:

  • Если вы не намерены изменять переменную, объявите ее как const.

    Если вы не изменяете переменную, о неожиданных изменениях речи не идет.

  • Сделайте переменную не - static. Удалите static квалификатор из объявления.

    Если переменная определена в функции, она становится регулярной локальной переменной. Если он задан в области файла, он становится переменной extern. Убедитесь, что это изменение в поведении то, что вы намереваетесь.

  • Сделайте функцию static. Добавление static квалификатор определения функции.

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

Примеры

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

/* file1. c  : contains inline definition of get_random()*/

inline unsigned int get_random(void) 
{

    static unsigned int m_z = 0xdeadbeef; 
    static unsigned int m_w = 0xbaddecaf; 

    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16); 
    m_w = 18000 * (m_w & 65535) + (m_w >> 16); 
    return (m_z << 16) + m_w;   
}


int call_get_random(void)
{
    unsigned int rand_no;
    int ii;
    for (ii = 0; ii < 100; ii++) {
         rand_no = get_random();
    }
    rand_no = get_random();
    return 0;
}
/* file2. c  : contains external definition of get_random()*/

extern unsigned int get_random(void)
{
    /* Initialize seeds */
    static unsigned int m_z = 0xdeadbeef;
    static unsigned int m_w = 0xbaddecaf;
    
    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;
}

В этом примере get_random() имеет встроенное определение в file1.c и внешнее определение в file2.c. Когда get_random вызывается file1.cкомпиляторы могут свободно выбирать, использовать ли встроенное или внешнее определение.

В зависимости от используемого определения, вы можете изменить или не изменить версию m_z и m_w в встроенном варианте get_random(). Такое поведение противоречит обычным ожиданиям от статической переменной. Когда вы звоните get_random(), вы ожидаете, что всегда измените то же самое m_z и m_w.

Коррекция - сделать встроенную функцию статической

Одна из возможных коррекций состоит в том, чтобы сделать встроенную get_random() статический. Независимо от вашего компилятора, звонки на get_random() в file1.c затем используйте inlined definition. Вызовы в get_random() в других файлах используйте внешнее определение. Это исправление удаляет неоднозначность в отношении того, какое определение используется и изменяются ли статические переменные в этом определении.

/* file1. c  : contains inline definition of get_random()*/

static inline unsigned int get_random(void) 
{

    static unsigned int m_z = 0xdeadbeef; 
    static unsigned int m_w = 0xbaddecaf; 

    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16); 
    m_w = 18000 * (m_w & 65535) + (m_w >> 16); 
    return (m_z << 16) + m_w;   
}


int call_get_random(void)
{
    unsigned int rand_no;
    int ii;
    for (ii = 0; ii < 100; ii++) {
         rand_no = get_random();
    }
    rand_no = get_random();
    return 0;
}
/* file2. c  : contains external definition of get_random()*/

extern unsigned int get_random(void)
{
    /* Initialize seeds */
    static unsigned int m_z = 0xdeadbeef;
    static unsigned int m_w = 0xbaddecaf;
    
    /* Compute next pseudorandom value and update seeds */
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;
}

Информация о результатах

Группа: Программирование
Язык: C | C++
По умолчанию: On для рукописного кода, off для сгенерированного кода
Синтаксис командной строки : INLINE_CONSTRAINT_NOT_RESPECTED
Влияние: Средний
Введенный в R2018a