Многие низкоуровневые программы используют ключевое слово volatile для типов для отображения памяти и тому подобного, однако я в некотором роде смущен тем, что ДЕЙСТВИТЕЛЬНО делает в фоновом режиме. Другими словами, что это значит, когда компилятор не «оптимизирует» адрес памяти?
9
volatile
переменной, и в нем написано 5, и вы читаете его снова в следующем году, вы гарантированно получите 6.Ответы:
volatile
означает, что какой-то другой процессор или устройство ввода-вывода или что-то может изменить переменную из-под вас.С помощью обычной переменной шаги вашей программы - единственное, что изменит ее. Так, например, если вы читаете
5
из переменной и не меняете ее, она все равно будет содержать5
. Поскольку вы можете положиться на это, ваша программа не должна тратить время на повторное чтение переменной в следующий раз, когда вы захотите ее использовать. Компилятор C ++ способен генерировать код, который просто запоминает5
.Но вы могли бы прочитать это как
5
, тогда, возможно, система загружает данные с диска в эту память, изменяя это на500
. Если вы хотите, чтобы ваша программа читала новое значение500
, вам нужно, чтобы компилятор не слишком умел использовать ранее прочитанное5
. Вы должны сказать ему, чтобы перезагрузить значение каждый раз. Вот чтоvolatile
делает.Аналогия для 5-летних.
Допустим, вы положили на стол большой лист бумаги. В одном углу бумаги вы записываете текущий счет текущей игры
3 to 4
. Затем вы идете на противоположную сторону стола и начинаете писать рассказ об игре. Ваш друг, который смотрит игру, обновляет счет в этом углу по ходу игры. Она стирает3 to 4
и пишет3 to 5
.Когда вы добавите счет в свою историю, вы можете:
3 to 4
весело предполагая, что он не изменился (или не обращая внимания, если он изменился), или3 to 5
сейчас), и вернитесь назад. Вот как действуетvolatile
переменная.источник
volatile
означает две вещи:Значение переменной может измениться без изменения вашего кода. Поэтому всякий раз, когда компилятор считывает значение переменной, он может не предполагать, что оно совпадает с последним разом, когда оно было прочитано, или что оно совпадает с последним сохраненным значением, но оно должно быть прочитано снова.
Акт сохранения значения в энергозависимой переменной является «побочным эффектом», который можно наблюдать извне, поэтому компилятору не разрешается удалять акт сохранения значения; например, если два значения хранятся в строке, тогда компилятор должен хранить значение дважды.
Например:
Компилятор должен сохранить номер два, прочитать переменную i, сохранить переменную, которую он прочитал в i.
Существует еще одна ситуация: если функция использует
setjmp
и затемlongjmp
вызывается, все энергозависимые локальные переменные функции гарантированно сохраняют последнее сохраненное значение - это не относится к энергонезависимым локальным переменным.источник
i
и значениеpi = &i
, тогдаx = *pi
выполняется чтение изi
, но это чтение не гарантирует изменчивую семантику.i
объявлено как,volatile int i
тоpi
должно быть объявлено какvolatile int *pi
, в каком случае*pi
это изменчивый доступ, нет?Абстрактное объяснение В
C и C ++ есть понятие абстрактной машины . Когда код использует значение некоторой переменной, абстрактная машина говорит, что реализация должна получить доступ к значению этой переменной. Код формы
statement_A; statement_B; statement_C;
должен быть выполнен в точно указанном порядке. Выражения, общие для этих трех операторов, должны пересчитываться каждый раз, когда они встречаются.За абстрактные машины, учитывая последовательность операторов
statement_A; statement_B; statement_C;
, реализация должна сначала выполнитьstatement_A
в полном объеме, а затемstatement_B
, и в конце концовstatement_C
. Реализация не может вспомнить, что вы присвоилиage
значение 5. Каждое утверждение, которое ссылается,age
должно вместо этого получить доступ к значению этой переменной.Не было бы необходимости в
volatile
ключевом слове, если реализации строго выполняли код C или C ++ согласно спецификациям абстрактной машины. В абстрактных машинах C и C ++ нет понятия регистров, нет понятия общих подвыражений, и порядок выполнения является строгим.Оба языка также имеют правила « как будто» . Реализация соответствует стандарту при условии, что эта реализация ведет себя так, как будто она выполнила все в соответствии со спецификацией абстрактной машины. Компилятор может предположить, что энергонезависимые переменные не изменяют значения между присваиваниями. Пока это не нарушает
as-if
правило, последовательностьstatement_A; statement_B; statement_C;
может быть реализована путем выполнения частиstatement_C
, затем частиstatement_A
, затем всегоstatement_B
, затем остальной частиstatement_A
и, наконец, остальной частиstatement_C
.Эти правила « как будто» не применяются к
volatile
переменным. Что касаетсяvolatile
переменных и функций, реализация должна делать именно то, что вы сказали ей делать, и именно в том порядке, в котором вы сказали ей делать вещи.Есть обратная сторона спецификации абстрактной машины: она медленная. Одним из положительных аспектов C и C ++ по сравнению с другими языками является то, что они довольно быстрые. Это не будет иметь место, если код был выполнен для этих абстрактных машин. Правила « как будто» позволяют C и C ++ быть такими быстрыми.
Ответ ELI5
«Оптимизация» адреса памяти - это продвинутая концепция, которая выходит за рамки возможностей пятилетнего ребенка. Податливые пятилетние дети будут делать именно то, что вы им скажете, ни больше, ни меньше. С помощью
volatile
этого вы говорите, что реализация действует так, как будто это пять: не нужно думать, не нужно ничего оптимизировать. Вместо этого реализация должна делать именно то, что говорит ей код.источник
(не) volatile - подсказка для компилятора, как оптимизировать код (с точки зрения сгенерированного кода сборки):
источник
Ответы кажутся довольно последовательными, но упускают важный момент. Вы говорите компилятору, что вы хотите выделить место, и для каждого доступа читайте ИЛИ ЗАПИСИ, вы хотите, чтобы он выполнял этот доступ. Мы не хотим, чтобы это по какой-то причине оптимизировало доступ или эту переменную.
Да, одна из причин в том, что кто-то другой может изменить это значение для нас. Другая причина в том, что мы можем изменить это значение для кого-то другого. То, что кто-то другой, кто меняет его для нас, или тот, на кого мы его меняем, может быть аппаратным / логическим или программным обеспечением. Он часто используется для определения доступа к элементам управления и регистрам состояния во встроенных программах с «голым железом», записи или аппаратного чтения. Так же как программное обеспечение, говорящее с программным обеспечением, объясненным в других ответах.
Вы также увидите, что volatile используется для управления тем, когда и в каком порядке происходит доступ, если вы пытаетесь рассчитать время для фрагмента кода и не используете volatile, то переменные (время начала, время окончания и разница) должны быть только вычисленный ближе к концу, компилятор может свободно перемещать любое из временных измерений (не туда, где мы их разместили), не то чтобы он не может изменяться, но опыт показывает, что это менее вероятно.
Иногда вы увидите, что раньше он просто сжигал время: элементарный мигающий светодиод, привет мир голого металла, мог использовать переменную для переменной, которая рассчитывает до некоторого большого числа, просто чтобы сжечь время, чтобы человеческий глаз увидел светодиод изменить состояние. Более сложные примеры, чем использование таймеров или других событий для записи времени.
источник