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

Может ли указатель быть изменчивым?

Рассмотрим следующий код:

int square(volatile int *p)
{
    return *p * *p;
}

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

Итак, что именно происходит, когда мы объявляем указатель как volatile?

Будет ли вышеупомянутый код работать, или он не отличается от этого:

int square(volatile int *p)
{
    int a = *p;
    int b = *p
    return a*b;
}

Можем ли мы умножить разные числа, поскольку указатели являются неустойчивыми?

Или есть лучший способ сделать это?

4b9b3361

Ответ 1

Может ли указатель быть volatile?

Абсолютно; любой тип, исключая функцию и ссылки, может быть volatile -qualified.

Обратите внимание, что volatile-указатель объявляется T *volatile, а не volatile T*, который вместо этого объявляет указатель на летучие.

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


int square(volatile int *p) { return *p * *p; }

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

Конкретный пример: допустим, у вас есть два массива int s

int a1 [] = { 1, 2, 3, 4, 5 };
int a2 [] = { 5453, -231, -454123, 7565, -11111 };

и указатель на один из них

int * /*volatile*/ p = a1;

с некоторой операцией на заостренных элементах

for (int i = 0; i < sizeof(a1)/sizeof(a1[0]); ++i) 
       *(p + i) *= 2;

здесь p должна быть прочитана каждая итерация, если вы сделаете ее volatile, потому что, возможно, она может фактически указывать на a2 из-за внешних событий.

Ответ 2

Да, вы можете, конечно, иметь изменчивый указатель.

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

Обратите внимание, что, когда в предыдущем абзаце говорится о "переупорядочении", предполагается один поток выполнения. Volatile не заменяет атомные операции или мьютексы/блокировки.

В более простых словах volatile обычно переводится как "Не оптимизируйте, просто делайте точно так, как я говорю".

В контексте указателя обратитесь к образцовому шаблону использования, данному Крисом Латтнером, известным "Что каждый программист должен знать о Undefined Поведение" article (да, эта статья о C, а не С++, но то же самое относится):

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

Ответ 3

Да. int * volatile.

В С++ ключевые слова в соответствии с типом/указателем/ссылкой идут после токена, например int * const является постоянным указателем на целое число, int const * является указателем на постоянное целое число, int const * const является постоянным указателем на постоянное целое e.t.c. Вы можете написать ключевое слово перед типом, только если оно для первого токена: const int x равно int const x.

Ответ 4

Ключевое слово volatile - это подсказка для компилятора (7.1.6.1/7):

Примечание: летучий является намеком на реализацию, чтобы избежать агрессивной оптимизации с участием объекта потому что значение объекта может быть изменено с помощью средств, необнаруживаемых реализацией. Более того, для некоторых реализаций, летучий может указывать на то, что для доступа требуются специальные аппаратные инструкции объект. Видеть  1,9  для детальной семантики. В общем, семантика летучий должны быть то же самое в C ++ как они находятся в C. - конечная нота ]

Что это значит? Ну, посмотрите на этот код:

bool condition = false;
while(!condition)
{
    ...
}

по умолчанию компилятор будет легко оптимизировать условие (он не изменяется, поэтому нет необходимости проверять его на каждой итерации). Если вы, однако, объявите условие как volatile, оптимизация не будет выполнена.

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

Ответ 5

В конце концов вы можете размножать разные числа, потому что они нестабильны и могут быть неожиданно изменены. Итак, вы можете попробовать что-то вроде этого:

int square(volatile int *p)
{
int a = *p;
return a*a;
}

Ответ 6

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

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

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