Встроенное ограничение, которое не уважают

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

Описание

Встроенное ограничение, которое не уважают, происходит, когда вы обращаетесь к файлу, определяют объем модифицируемой статической переменной или задают локальную модифицируемую статическую переменную в нестатической встроенной функции. Средство проверки рассматривает переменную как модифицируемую, если это не const - квалифицированный.

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

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++;
}

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

Фиксация

Используйте одни из этих мер:

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

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

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

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

  • Сделайте функциональный 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 затем используют встроенное определение. Вызовы 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++
Значение по умолчанию: на
Синтаксис командной строки: INLINE_CONSTRAINT_NOT_RESPECTED
Влияние: носитель

Введенный в R2018a