ПроблемаВстроенное ограничение не соблюдается при ссылке на изменяемую статическую переменную области действия файла или определении локальной изменяемой статической переменной в нестатической встроенной функции. Средство проверки считает переменную изменяемой, если она не является 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++;
}Если функция имеет определение inlined и non-inlined (в отдельных файлах), при вызове функции стандарт C позволяет компиляторам использовать либо inlined, либо non-inlined форму (см. ISO ®/IEC 9899:2011, sec. 6.7.4). Если компилятор использует встроенное определение в одном вызове, а неинлинированное определение в другом, изменение одной и той же переменной в обоих вызовах больше не выполняется. Это поведение не соответствует ожиданиям от статической переменной.
ЗафиксироватьИспользуйте одно из следующих исправлений:
Если изменение переменной не планируется, объявите ее как const.
Если переменная не изменяется, то о неожиданном изменении речи не идет.
Сделать переменную не -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;
}