Разница между const и const volatile - PullRequest
78 голосов
/ 04 января 2011

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

Тогда const volatile int temp;
Какая польза от объявления переменной temp, как указано выше?
Что произойдет, если мы объявим const int temp?

Ответы [ 10 ]

121 голосов
/ 04 января 2011

Объект, помеченный как const volatile, не может быть изменен кодом (ошибка будет возникать из-за спецификатора const) - по крайней мере, через это конкретное имя / указатель.

Часть volatile в классификаторе означает, что компилятор не может оптимизировать или изменить порядок доступа к объекту.

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

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

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

Быстрый пример:

unsigned int const volatile *status_reg; // assume these are assigned to point to the 
unsigned char const volatile *recv_reg;  //   correct hardware addresses


#define UART_CHAR_READY 0x00000001

int get_next_char()
{
    while ((*status_reg & UART_CHAR_READY) == 0) {
        // do nothing but spin
    }

    return *recv_reg;
}

Если эти указатели не были помечены как volatile, может возникнуть пара проблем:

  • при проверке цикла while можно прочитать регистр состояния только один раз, посколькукомпилятор может предположить, что все, на что он указывал, никогда не изменится (в цикле while или в самом цикле нет ничего, что могло бы его изменить).Если вы вошли в функцию, когда в оборудовании UART не было ожидающих символов, вы можете оказаться в бесконечном цикле, который никогда не останавливался даже при получении символа.
  • чтение регистра приема может быть перемещенокомпилятор перед циклом while - опять же, поскольку в функции нет ничего, что указывало бы на то, что *recv_reg изменяется циклом, нет причины, по которой его нельзя прочитать перед входом в цикл.

Спецификаторы volatile гарантируют, что эти оптимизации не выполняются компилятором.

34 голосов
/ 04 января 2011
  • volatile скажет компилятору не оптимизировать код, связанный с переменной, обычно, когда мы знаем, что она может быть изменена извне, например, другим потоком.
  • const скажеткомпилятор, который запрещает программе изменять значение переменной.
  • const volatile - это очень особенная вещь, которую вы, вероятно, увидите, использовался ровно 0 раз в вашей жизни (tm).Как и следовало ожидать, это означает, что программа не может изменить значение переменной, но значение может быть изменено извне, поэтому оптимизация переменной не будет выполняться.
24 голосов
/ 04 января 2011

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

Constness - это обещание, которое вы даете, чтобы не изменять значение, а не то, что значение не будет изменено.

7 голосов
/ 28 июня 2015

Мне нужно было использовать это во встроенном приложении, где некоторые переменные конфигурации расположены в области флэш-памяти, которая может быть обновлена ​​загрузчиком.Эти переменные конфигурации являются «постоянными» во время выполнения, но без квалификатора volatile компилятор оптимизирует что-то вроде этого ...

cantx.id = 0x10<<24 | CANID<<12 | 0;

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

5 голосов
/ 09 августа 2016

В C const и volatile являются определителями типа, и эти два являются независимыми.

По сути, const означает, что значение не может быть изменено программой.

И изменчивый означает, что значение может быть внезапно изменено (возможно, из-за пределов программы).

Фактически, стандарт C упоминает пример действительного объявления, которое является как постоянным, так и изменчивым. Пример

«extern const volatile int real_time_clock;»

где real_time_clock может быть изменен аппаратно, но не может быть назначен, увеличен или уменьшен.

Так что мы должны уже рассматривать const и volatile отдельно. Кроме того, эти классификаторы типов применяются также для struct, union, enum и typedef.

3 голосов
/ 23 декабря 2016

Вы можете использовать const и volatile вместе. Например, если 0x30 предполагается значением порта который изменяется только внешними условиями, следующая декларация исключит любую случайных побочных эффектов:

const volatile char *port = (const volatile char *)0x30;
3 голосов
/ 15 ноября 2015

В этой статье рассматриваются сценарии, в которых вы хотите объединить const и volatile квалификаторы.

http://embeddedgurus.com/barr-code/2012/01/combining-cs-volatile-and-const-keywords/

3 голосов
/ 30 сентября 2015

const означает, что переменная не может быть изменена кодом c, но не может быть изменена.Это означает, что никакая инструкция не может записать в переменную, но ее значение все еще может измениться.

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

Поскольку вопрос помечен как «встроенный», и предполагается, что temp является объявленной пользователем переменной, а не аппаратным регистром (так как обычно этообрабатывается в отдельном файле .h), рассмотрим:

Встроенный процессор, который имеет как энергозависимую память для чтения-записи (RAM), так и энергонезависимую постоянную память для данных, например, FLASH-память в von-Neumannархитектура, в которой данные и пространство программ совместно используют общую шину данных и адресов.

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

В результате:

int temp; - это переменная, хранящаяся в ОЗУ, инициализируемая в 0 при запуске (cstart), кэшированные значения могут бытьused.

const int temp; - переменная, хранящаяся во флэш-памяти (только для чтения), инициализированная значением 0 во время компиляции, могут использоваться кэшированные значения.

volatile int temp; - переменная, хранящаяся вОЗУ, инициализированное в 0 при запуске (cstart), кэшированные значения НЕ будут использоваться.

const volatile int temp; - переменная, хранящаяся во флэш-памяти (только для чтения), инициализированная в 0 во время компиляции, кэшированные значения НЕ будутиспользоваться

Вот полезная часть:

В настоящее время большинство встроенных процессоров имеют возможность вносить изменения в свою постоянную память только для чтения с помощью специального функционального модуля, в этом случаеconst int temp можно изменить во время выполнения, но не напрямую.Другими словами, функция может изменить значение по адресу, где хранится temp.

Практическим примером будет использование temp для серийного номера устройства.При первом запуске встроенного процессора значение temp будет равно 0 (или объявленному значению), и функция может использовать этот факт для запуска теста во время производства, а в случае успеха попросить присвоить серийный номер и изменить значение.temp с помощью специальной функции.Некоторые процессоры имеют специальный диапазон адресов с OTP (одноразовой программируемой) памятью только для этого.

Но здесь возникает разница:

Если const int temp является изменяемым идентификатором вместо одноразового программируемого серийного номера и НЕ объявляется volatile, может использоваться кэшированное значениедо следующей загрузки, это означает, что новый идентификатор может быть недействительным до следующей перезагрузки, или, что еще хуже, некоторые функции могут использовать новое значение, в то время как другие могут использовать более старое кэшированное значение до перезагрузки.Если const int temp IS объявлено voltaile, изменение идентификатора вступит в силу немедленно.

1 голос
/ 30 июля 2018

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

1 голос
/ 17 ноября 2015

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

...