Здесь есть две ошибки. Первый из них:
int *ptr_to_const = &const_val;
, что является нарушением ограничения в соответствии с C11 6.5.4 / 3 (более ранние стандарты имели похожий текст):
1010 * Ограничения *
Преобразования, в которых используются указатели, отличные от тех, которые разрешены ограничениями из 6.5.16.1, должны быть определены посредством явного приведения
Преобразование из const int *
в int *
недопустимо из-за ограничений 6.5.16.1 (которые можно посмотреть здесь ).
Смущает, что когда некоторые компиляторы сталкиваются с нарушением ограничения, они пишут «предупреждение» (или даже вообще ничего, в зависимости от переключателей) и делают вид, что вы написали что-то еще в своем коде, и продолжаете. Это часто приводит к программам, которые ведут себя не так, как ожидал программист, или фактически не ведут себя каким-либо предсказуемым образом. Почему компиляторы делают это? Бьет меня, но это, безусловно, создает бесконечный поток подобных вопросов.
gcc, похоже, работает так, как если бы вы написали int *ptr_to_const = (int *)&const_val;
.
Этот фрагмент кода не является нарушением ограничения, поскольку используется явное приведение. Однако это подводит нас ко второй проблеме. Затем строка *ptr_to_const = 20;
пытается выполнить запись в объект const
. Это вызывает неопределенное поведение , соответствующий текст из Стандарта находится в 6.7.3 / 6:
Если предпринята попытка изменить объект, определенный с помощью const-квалифицированного типа, с помощью lvalue с неконстантным типом, поведение не определено.
Это правило семантическое, а не ограничение, что означает, что стандарт не требует, чтобы компилятор выдавал какие-либо предупреждения или сообщения об ошибках. Программа просто неверна и может вести себя бессмысленно, с любыми странными симптомами, включая, помимо прочего, то, что вы наблюдали.