6.46 Когда происходит доступ к объекту volatile? ¶
В языке C существуют переменные типа volatile. К ним обычно обращаются через указатели и используются для доступа к аппаратуре или межпотоковой коммуникации. Стандарт рекомендует компиляторам воздерживаться от оптимизаций, связанных с доступом к переменным volatile, но оставляет за реализацией определение того, что считается доступом volatile. Минимальное требование заключается в том, что в точке последовательности все предыдущие обращения к переменным volatile стабилизировались, и никаких последующих обращений не произошло. Таким образом, реализация свободна переупорядочивать и комбинировать обращения к volatile, которые происходят между точками последовательности, но не может делать этого для обращений через точку последовательности. Использование volatile не позволяет нарушать ограничение на многократное обновление объектов между двумя точками последовательности.
Доступ к не-volatile объектам не упорядочен относительно volatile обращений. Вы не можете использовать volatile объект как барьер памяти для упорядочивания последовательности записей в не-volatile память. Например:
int *ptr = something; volatile int vobj; *ptr = something; vobj = 1;
Если *ptr и vobj не могут быть алиасами, нет гарантии, что запись в *ptr произойдет к моменту обновления vobj. Если вам нужна такая гарантия, необходимо использовать более сильный барьер памяти, такой как:
int *ptr = something;
volatile int vobj;
*ptr = something;
asm volatile ("" : : : "memory");
vobj = 1;
Скалярный volatile объект считывается, когда к нему обращаются в контексте void:
volatile int *src = somevalue; *src;
Такие выражения являются rvalue, и GCC реализует это как чтение volatile объекта, на который указывает указатель.
Присваивания также являются выражениями и имеют rvalue. Однако при присваивании скалярному volatile объекту volatile объект не перечитывается, независимо от того, используется ли rvalue выражения присваивания или нет. Если rvalue присваивания используется, значение — это значение, присвоенное volatile объекту. Например, нет чтения vobj во всех следующих случаях:
int obj; volatile int vobj; vobj = something; obj = vobj = something; obj ? vobj = onething : vobj = anotherthing; obj = (something, vobj = anotherthing);
Если вам нужно прочитать volatile объект после того, как присваивание произошло, вы должны использовать отдельное выражение с промежуточной точкой последовательности.
Так как битовые поля не могут быть индивидуально адресованы, volatile битовые поля могут быть неявно прочитаны при записи в них или при доступе к соседним битовым полям. Операции с битовыми полями могут быть оптимизированы таким образом, что соседние битовые поля только частично доступны, если они пересекают границу ячейки хранения. По этим причинам не рекомендуется использовать volatile битовые поля для доступа к аппаратуре.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-10.5.0/gcc/Volatiles.html