Изменение переменной const с помощью ключевого слова volatile

Я отвечал на вопрос и сделал эту тестовую программу.

#include  int main() { volatile const int v = 5; int * a = &v; *a =4; printf("%d\n", v); return 0; } 

Без ключевого слова volatile код оптимизируется (скомпилирован с -O3 apple clang 4.2) с изменением var, поскольку он работает так, как ожидалось, и переменная const изменяется правильно.

Мне было интересно, знает ли более опытный разработчик C, есть ли часть стандарта, который говорит, что это небезопасно или UB.

UPDATE: @EricPostpischil дал мне эту стандартную цитату

Программа не может изменять свой собственный объект, определенный с использованием типа const, в C 2011 (N1570). 6.7.3 6: «Если делается попытка изменить объект, определенный с использованием типа const, используя значение l с неконстантно-квалифицированный тип, поведение не определено ». Внешний агент может модифицировать объект, который имеет тип с изменчивой квалификацией, в соответствии с 6.7.3 7:« Объект, который имеет изменчивый тип, может быть изменен способами, неизвестными реализация или другие неизвестные побочные эффекты

Моя программа нарушает первое правило, но я думал, что второе правило может освободить программу от первого.

ОБНОВЛЕНИЕ 2:

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

Если вы посмотрите на эту цитату, вы можете увидеть, что var должен быть оценен в соответствии с определенными правилами, я не прочитал весь раздел 5.1.2.3 но я считаю, что это может пролить свет на проблему.

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

Эта строка:

 int * a = &v; 

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

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

Чтобы соответствовать стандарту C, указатель должен иметь свой указательный тип с теми же или более сильными квалификаторами, на которые указывает объект, например:

 int const volatile *a = &v; 

после чего вы увидите, что линия *a = 4; вызывает ошибку компиляции.


Возможная попытка:

 int *a = (int *)&v; 

Эта строка должна компилироваться, но затем она вызывает неопределенное поведение для чтения или записи через *a . Неопределенное поведение задается C11 6.7.3 / 6 (C99 и C89 имеют аналогичный текст):

Если предпринимается попытка изменить объект, определенный с помощью типа, соответствующего const, с использованием значения lvalue с неконстантированным classом, поведение не определено. Если делается попытка обратиться к объекту, определенному с помощью типа с изменчивой квалификацией, с использованием значения lvalue с типом, не зависящим от летучих, поведение не определено.