Подтвердить что ты не робот

Каково использование ключевого слова volatile?

Каково использование ключевого слова volatile в C/С++? В чем разница между объявлением переменной volatile и не объявлением ее как volatile?

4b9b3361

Ответ 1

Квалификатор volatile сообщает компилятору, что всякий раз, когда вы обращаетесь к переменной, ее значение должно быть загружено из памяти и что он может ничего не принимать в отношении этого значения из предыдущих сохраненных им хранилищ.

Поэтому он подходит, когда у вас есть ситуации, когда переменная может иметь значение, которое не может быть предусмотрено в текущем "потоке выполнения" (в широком смысле). Это включает в себя:

  • аппаратные регистры
  • переменные состояния в обработчиках сигналов
  • переменные, которые используются после неожиданные скачки, такие как goto, switch/case, или, что более важно, setjmp/longjmp.

volatile также необходим (но не достаточно!) для атомарного доступа к потоковым общим переменным, к которым доступ не мьютексирован. Для этого volatile отнюдь не является достаточным для обеспечения доступа атома, даже если он предназначен только для чтения. Для этого вам придется использовать специальные инструкции CPU, которые не моделируются (или сопрягаются) абстрактной машиной текущего стандарта C, C99. Следующий стандарт C1X должен иметь такие примитивы.

Ответ 2

Volatile сообщает компилятору, что переменная может измениться без его знания - поэтому он не должен ее оптимизировать.

Единственное время, которое мне когда-либо понадобилось, было в дни карт ISA, когда вы читали адрес памяти, чтобы получить данные с шины. В компиляторе также была ошибка, которая означала, что volatile не работает!

Он также может быть полезен в некотором параллельном /mutli -threaded кодеке

Ответ 3

Volatile сообщает компилятору, что это значение может измениться, и компилятор не должен делать никакой оптимизации на нем. Пример этого.

/** port to read temperature **/
#define PORTBASE 0x40000000

unsigned int volatile * const port = (unsigned int *) PORTBASE; 

for(;;)
{
  if(*port == 300)
  {
     /** shutdown the system **/
  }

}

Если порт нестабилен, тогда компилятор будет считать, что значение не может быть изменено. Он никогда не будет проверять, если * port == 300. Однако значение может быть изменено на основе датчика. Мы ставим volatile, чтобы сообщить компилятору, что на нем нет никакой оптимизации. Правило Thumb заключается в использовании регистров с отображением памяти, значение которых может меняться в зависимости от обстоятельств, а затем использовать ключевое слово volatile.

Ответ 4

Для большинства программ C цель объекта состоит в том, чтобы удерживать последнее, что было написано кодом в текущем контексте выполнения ( "поток", ядро ​​ЦП и т.д.). Самый простой способ для компилятора отслеживать содержимое объекта - это выделять пространство в хранилище и обрабатывать чтение и запись этой переменной как чтение и запись этого хранилища, но само хранилище не представляет цели кода - он просто представляет собой средство для достижения цели. Учитывая unsigned x;, если компилятор видит x+=3; x+6;, самым простым способом сгенерировать код будет выборка x, добавление 3, сохранение результата в x, затем выборка x, добавление 6 и сохранение этого результата. Однако промежуточная нагрузка и хранилище необходимы только тогда, когда компилятор не знает, как добиться такого же эффекта каким-либо другим способом. Лучший компилятор с таким кодом часто мог бы упростить его, просто добавив 9.

Тем не менее, особенно во встроенном или системном коде, целью программы может быть загрузка и сохранение определенных значений из определенных мест хранения в определенной последовательности. Многие машины реального мира выполняют операции ввода-вывода, используя оборудование, которое запускается нагрузками и хранилищами определенных объектов, и выполняет различные действия в ответ. Например, было бы нередко иметь объект, который при правильных условиях приводил бы к передаче любого символа, передаваемого ему, в терминал. Например, сохранение "H" и "i" в SERTX может отправить Hi. Наличие компилятора для упрощения или консолидации таких последовательностей (например, решение опустить хранилище "H" ) сделает программы бесполезными. Атрибут volatile указывает компилятору, что, хотя он может свободно консолидировать большинство обращений к большинству объектов, есть несколько, для которых такие обращения должны выполняться точно так же, как написано. Эффективно можно представить, что для каждого типа скаляра (например, "без знака" ) существуют функции

int volatile_load_unsigned(unsigned volatile *p);
void volatile_store_unsigned(unsigned volatile *p, usigned value);

поведение которого компилятор ничего не знает и, таким образом, выглядит так:

extern volatile unsigned x;
x+=3;
x+=6;

будет интерпретироваться компилятором как эквивалент:

extern volatile int x;
volatile_store_unsigned(&x, volatile_load_unsigned(&x)+3);
volatile_store_unsigned(&x, volatile_load_unsigned(&x)+6);

Фактически, машинный код для выполнения энергозависимого хранилища находится в большинстве систем то же, что и код для обычного хранилища (и не генерирует никакого рода вызова функции), но только часть компилятора, которая генерирует окончательный машинный код "знал бы", что - все остальное должно лечить код, как будто это была функция, эффекты которой компилятор ничего не знал о.

К сожалению, во имя "оптимизации" некоторые компиляторы прекратили рассматривая нестабильные обращения как вызовы непрозрачных функций. Если вызов кода функция, внутренняя работа которой компилятор ничего не знает о ней должен предполагать, что функция может обращаться к любым и всем объектам, адрес которых когда-либо подвергался воздействию внешнего мира. Применение такого лечения для volatile -квалифицированные переменные позволят коду строить объект в обычное хранилище, используя возможность консолидировать нагрузки и сохраняет, сохраняют адрес этого объекта в соответствии с изменчивой квалификацией указатель, запускающий другой процесс, который выводит буфер. Код необходимо будет проверить объект с изменчивой квалификацией, чтобы гарантировать, что содержимое буфера были полностью выведены, прежде чем делать что-либо еще с этим хранилищем, но в реализациях, которые следуют модели "непрозрачной функции", компилятор будет гарантировать, что все записи в хранилище, которые произошли в коде, прежде чем энергозависимое хранилище, которое запускает операцию вывода, фактически будут генерировать инструкции хранилища, которые предшествуют инструкции для энергосберегающий магазин.

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

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

Ответ 5

Volatile сообщает компилятору, что значение переменной может быть изменено за пределами области вашего кода для ex.

{
 int x; 
 int y;
}

Значение x и y ограничено областью действия, но в случае, если мы изменяем его значение откуда-то вне, тогда оно должно быть помечено как volatile, потому что компилятор будет хранить эти значения во временном регистре и всегда давать то же значение вместо давая измененное значение.

Поэтому в таких случаях необходимо использовать volatile, чтобы получить последнее значение этой конкретной переменной.

Ответ 6

volatile ограничивает компилятор не оптимизацией использования конкретной переменной, которая объявляется изменчивой в коде.

Разница между переменной с изменчивой и без нее

Переменная Без летучих

int main()    
{    
    int a = 5;

    while(a == 5)  //compiler replace variable **'a'** with 5 as optimization purpose    
    {        
    }

    if(a==5)//compiler replace **'a'** with 5 as optimization purpose    
    {    
    }

    return 0;    
}

в вышеприведенном компиляторе кода предположим, что значение переменной 'a' всегда будет 5, поэтому компилятор заменит все 'a' на 5 в качестве цели оптимизации.

Переменная с изменчивым

Но некоторые значения переменных изменяются внешним прерыванием, поэтому здесь нам всегда нужно получить это значение переменных непосредственно из памяти. Для этой цели мы используем volatile.

volatile int a=5;

while(a==5) //compiler will npt optimize the variable **'a'** and always get the value of **'a'** from Memory 

Ответ 7

когда мы используем простую нелетучую переменную в то время, компилятор попытается оптимизировать код, например, если вы используете b = a * a * a; то он будет использоваться как b = a * 3; но когда вы используете ключевое слово volatile при объявлении переменной "a", тогда оптимизация не будет иметь место для значения "a", и каждый раз, когда значение будет извлечено из памяти, поскольку изменчивый Qualifier позволит другим аппаратным средствам а также процесс изменения значения переменной.