Почему полезен указатель "точка-volatile", например "volatile int * p"?

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

volatile int *p = some_addr;
int a = *p; // CPU always has to load the address, then does a memory access anyway, right?

В чем разница, если он был объявлен как int *p = some_addr?

Ответ 1

Указатель формы

volatile int* p;

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

Существует еще один вариант использования volatile int*: если вы объявляете int как volatile, вам не следует указывать на него обычным int*. Например, это плохая идея:

volatile int myVolatileInt;
int* ptr = &myVolatileInt; // Bad idea!

Причина этого заключается в том, что компилятор C больше не помнит, что переменная, на которую указывает ptr является volatile, поэтому он может неправильно кэшировать значение *p в регистре. Фактически в C++ приведенный выше код является ошибкой. Вместо этого вы должны написать

volatile int myVolatileInt;
volatile int* ptr = &myVolatileInt; // Much better!

Теперь компилятор запоминает, что ptr указывает на volatile int, поэтому он не будет (или не должен!) Пытаться оптимизировать доступ через *ptr.

Одна последняя деталь - указатель, который вы обсуждали, является указателем на volatile int. Вы также можете сделать это:

int* volatile ptr;

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

volatile int* volatile ptr;

Это говорит о том, что указатель и указатель могут быть неожиданно изменены. Компилятор не может оптимизировать сам указатель и не может оптимизировать то, на что он указывает.

Надеюсь это поможет!

Ответ 2

Этот код volatile int *p = some_addr объявляет указатель на volatile int. Сам указатель не volatile.

В маловероятном случае, когда вам понадобился указатель на переменную, а также на int, вам нужно будет использовать:

volatile int * volatile p;

Я не могу думать о ситуации, когда вам нужно будет это использовать.

Ответ 3

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