Я отвечал на вопрос и сделал эту тестовую программу.
#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 с типом, не зависящим от летучих, поведение не определено.