ПроблемаНе соблюдаемое ограничение Inline возникает, когда вы ссылаетесь на изменяемую статическую переменную области файла или задаете локальную изменяемую статическую переменную в нестатической встроенной функции. Проверка рассматривает переменную как изменяемую, если она не 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 и nonlinined определение в отдельных файлах, когда вы вызываете функцию, стандарт C позволяет компиляторам использовать inlined или noninlined форму (см. ISO®/ IEC 9899:2011, с. 6.7.4). Если ваш компилятор использует inlined определение в одном вызове и nonlinined описание в другом, вы больше не изменяете одну и ту же переменную в обоих вызовах. Это поведение бросает вызов ожиданиям от статической переменной.
ЗафиксироватьИспользуйте одно из следующих исправлений:
Если вы не намерены изменять переменную, объявите ее как const
.
Если вы не изменяете переменную, о неожиданных изменениях речи не идет.
Сделайте переменную не - static
. Удалите static
квалификатор из объявления.
Если переменная определена в функции, она становится регулярной локальной переменной. Если он задан в области файла, он становится переменной extern. Убедитесь, что это изменение в поведении то, что вы намереваетесь.
Сделайте функцию static
. Добавление static
квалификатор определения функции.
Если вы делаете функцию static
файл с встроенным определением использует встроенное определение при вызове функции. Другие файлы используют другое определение функции. Компилятор не решает, какое определение функции используется.
Пример - Использование статических переменных в Inlined и Внешнем определении/* file1. c : contains inline definition of get_random()*/
inline unsigned int get_random(void)
{
static unsigned int m_z = 0xdeadbeef; //Noncompliant
static unsigned int m_w = 0xbaddecaf; //Noncompliant
/* 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; //Compliant
static unsigned int m_w = 0xbaddecaf; //Compliant
/* 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;
}