Разница между const и const volatile

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

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

Ответ 1

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

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

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

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

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

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

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 гарантируют, что эти оптимизации не выполняются компилятором.

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

В принципе, const означает, что значение не модифицируется программой.

И volatile означает, что значение подвержено внезапному изменению (возможно, вне программы).

Фактически, в стандарте C упоминается пример действительной декларации, которая является как const, так и изменчивой. Пример:

"extern const volatile int real_time_clock;"

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

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

Ответ 6

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

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

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

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

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

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

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

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

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

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

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

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

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

Но здесь приходит разница:

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

Ответ 8

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

const volatile char *port = (const volatile char *)0x30;

Ответ 9

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