Зміна констант базових типів - stack overflow російською

Хотілося б зрозуміти, як С ++ обробляє константи базових типів.

Що буде, якщо за допомогою танців з бубном і покажчиками змінити значення, що знаходиться в комірці пам'яті, де, по ідеї, і повинна міститися константа?

Є наступний код:

Висновок у мене виходить наступний:

Як пояснити таку поведінку?

Я не збираюся такий код ніколи використовувати на практиці, просто хочу зрозуміти, де зберігаються константи.

Для початку: за стандартом, зміна за допомогою трюків з покажчиками констант є undefined behaviour. Може статися все, що завгодно в будь-якій точці програми.

Гірше того, якщо десь компілятор з'ясував для себе, що константа парна, і її молодший біт дорівнює 0, і на підставі цієї інформації зміг виключити якісь перевірки з коду, то тепер перевірки не пройдуть, і код може крешнуться в будь-який момент .

На UB зазвичай засновані діри в безпеці програм. Наприклад, якщо компілятор обгрунтовано вважає, що довжина рядка 45, і під неї достатньо виділити буфер такої довжини, в той час як ви, обдуривши компілятор, підсуне йому рядок довжиною 54, вийде класичний зрив стека.

Резюме: У компілятора немає ніяких «зобов'язань» або «принципів» по ​​роботі з константами. Він має право робити що завгодно. Навпаки, це програміст, якщо вже обіцяв, що якесь значення є константа, не має права його змінювати.

Відповідно до стандарту C ++ (7.1.6.1 The cv-qualifiers)

4 Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior

Є один анахронізм в C, коли навіть спроба змінити неконстантний об'єкт призводить до невизначеного поведінки програми. Йдеться про строкових літералах в мові C.

У C ++ рядкові літерали мають типи константних символьних масивів. Наприклад, строковий літерал "Hello" має тип const char [6]. Однак в C рядкові літерали мають типи неконстантних символьних масивів. Тому цей же самий строковий літерал "Hello" в C має тип char [6]. Проте ви не можете змінити строковий літерал в C, також як ви не можете змінити строковий літерал в C ++.

З стандарту C (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

Те, що в C рядкові літерали мають типи неконстантних символьних масивів, очевидно пов'язано з підтримкою вже існуючої кодової бази на момент введення кваліфікатора const в стандарт мови C.

Компілятор розумний і знає, що константу можна заінлайніть. Але є можливість переконати його, що ця константа не надто константная:

PS: Наскільки я пам'ятаю, volatile const це коректна ситуація, яка не повинна призводити до undefined behavior.

він має повне право припускати, що свій код точно не змінює const-об'єкти.

Для volatile це неважливо. Уявімо, що є щось зовнішнє, що "абсолютно випадково" змінює ту ж константу на ті ж значення, що ми написали. А в самій програмі замість змінює коду стоять nop'и. Такий варіант абсолютно точно коректний і не викликає UB.

Схожі статті