Когда отбрасывание const является законным или незаконным? (gcc, clang и MSVC)

Когда изгоняется const незаконный?

Во многих случаях const это просто аннотация для пользы пользователя, которая обеспечивается компилятором. Этот вопрос задают при отбрасывании const является строго незаконным, и какая часть стандарта C99 запрещает это (если есть)?

Я подозреваю, что это должно быть незаконно в некоторых случаях, потому что я заметил, что const указатели на функции в глобальной области видимости иногда указываются gcc. Если бы эти указатели функций могли быть юридически изменены позже в программе, то эта оптимизация была бы недействительной. Кроме того, я почти уверен, что прочитал объяснение const незаконно в Stackru, но я просто не могу его найти. (Я думаю, что ответ был const может быть отброшено, только если переменная не была объявлена ​​как const.)

Я пометил этот C99, потому что я надеюсь, что это что-то определено в стандарте C99, но если ответ может объяснить поведение, общее для реализаций C99 gcc, clang и MSVC, то этого также будет достаточно для меня.

(Очевидно, это очень простой вопрос, поэтому я попытался и не смог найти дубликат специально для стандарта C. Если кто-то еще может указать мне точный дубликат, я буду рад закрыть голосование. В любом случае, я думаю, что этот вопрос название по крайней мере помогает SSO для такого рода вопроса.)

1 ответ

Решение

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

С99 четко заявляет

6.7.3 Классификаторы типов

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

(это 6.7.3/6 в C11).

Обратите внимание, что const в C (и C++) используется в двух независимых и очень разных ролях: const-квалификация самого объекта и const-квалификация пути доступа к объекту.

const int a = 42;  // `a` is a const-qualifiet object

int b = 5;         // `b` is not const-qualified
const int *p = &b; // `*p` is a const-qualified access path to `b`

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

*(int *) p = 6; // nothing formally wrong with it

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

Но первое (постоянство самого объекта) не может быть переопределено

*(int *) &a = 43; // undefined behavior

Причина довольно тривиальна - константный объект может быть физически размещен в постоянной памяти. И даже если это не так, компилятор все еще может компилировать код, предполагая, что значение объекта никогда не изменится.

Это означает, что в объявлении типа

const int *const cp = &b;

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

Итак, когда вы говорите, что "const это просто аннотация для пользы пользователя, которая обеспечивается компилятором ", это справедливо только для const-квалификаций путей доступа. Когда речь идет о const-квалификациях самих объектов, обычно это намного больше, чем просто чисто концептуальная "аннотация", поддерживаемая компилятором.

Другие вопросы по тегам