Я смотрю на следующий код:
inline void* interlocked_read_acquire(void* volatile* x);
и мне интересно, почему не просто volatile void*
в качестве аргумента. В общем, что такое семантика или определение volatile*
? Я также делаю предположение, что вы могли бы использовать volatile*
классификатор с любым другим типом, кроме void. Это верно?
использование Cdecl или спиральное правило по часовой стрелке расшифровать объявления в стиле C:
void* volatile* x
который отличается от:
volatile void* x
интересно, почему [
void* volatile*
и] не простоvolatile void*
…?
Это разные вещи.
void* volatile*
это указатель на переменную (void*
) (поэтому разыменование и доступ к volatile void*
возможно без кастинга, но просто даст вам адрес какой-то пока еще не указанной вещи в памяти)
volatile void*
это указатель на изменчивый void
(так что вы должны привести к типу, как, скажем, volatile int*
или же volatile My_Class*
до разыменования)
void * ptr1;
Значит это ptr1
переменная, тип которой void *
, Этот тип указывает «универсальный указатель» — он указывает на некоторую ячейку памяти, но не содержит информации о типе того, что находится в этой ячейке.
void * volatile ptr2;
означает, что переменная ptr2
также является общим указателем, но ptr2
это также volatile
, Ключевое слово volatile
называется резюме-классификатор и имеет те же правила грамматики, что и const
,
Значение изменчивой переменной состоит в том, что когда некоторый другой код говорит ptr2
компилятор не может оптимизировать это; он должен прочитать или записать место в памяти, где ptr2
хранится; он должен учитывать возможность того, что какой-то внешний процесс также читает или записывает это местоположение.
В заключение, void * volatile *x
это то, что может указывать на ptr2
, Например, мы могли бы иметь void * volatile * x = &ptr2;
, Если мы тогда напишем *x = NULL;
например, тогда *x
имеет тип void * volatile
что имеет те же последствия, как мы только что посмотрели на ptr2
,
Компилятор будет жаловаться, если вы опустите классификатор, например void * *y = &ptr2;
, Это потому что выражение *y
будет иметь тип void *
(энергонезависимый), поэтому компилятор может выполнять оптимизацию вокруг него, однако это неправильное поведение, потому что ptr2
не разрешает эти оптимизации. (Вы можете признать, что «изменчивость-правильность» — это то же самое, что и постоянная-корректность).
volatile — это дополнительное свойство, вы можете сначала удалить его для чтения из
void* volatile* x
чтобы:
void* *x
Это очень знакомо. Например, массив неправильно распределенных указателей памяти.
И вы не запутаетесь с
volatile void*
который сводится к
void* x.