Чи є переповнене цілочисельним переповненням все ще невизначеною поведінкою в C ++?


84

Як ми знаємо, переповнення цілим числом із підписом є невизначеною поведінкою . Але в документації C ++ 11 є щось цікаве cstdint:

підписаний цілочисельний тип із шириною рівно 8, 16, 32 та 64 біта відповідно без бітів заповнення та використовуючи доповнення 2 для від’ємних значень (надається лише у тому випадку, якщо реалізація безпосередньо підтримує тип)

Див. Посилання

І ось моє запитання: так як стандарт прямо говорить , що для int8_t, int16_t, int32_tі int64_tнегативних чисел 2 - х комплемент, по - , як і раніше переповнення цих типів невизначеного поведінки?

Редагувати Я перевірив стандарти C ++ 11 та C11, і ось що я знайшов:

C ++ 11, § 18.4.1:

Заголовок визначає всі функції, типи та макроси так само, як 7.20 у стандарті C.

C11, § 7.20.1.1:

Ім'я typedef intN_tпозначає підписаний цілий тип із шириною N, без бітів заповнення та поданням доповнення двох. Таким чином, int8_tпозначає такий підписаний цілий тип із шириною рівно 8 біт.


14
Ніколи не забувайте, що єдиною основною документацією для C ++ є стандарт. Все інше, навіть така вікі, як CppReference, є вторинним джерелом. Це не означає, що це неправильно; просто не зовсім надійний.
Nicol Bolas

Я би очікував, що це буде UB, для C не існує винятків для цих типів, я не розумію, чому C ++ додав би такий.
Даніель Фішер,


3
Я трохи заплутався: де дієслово у реченні "підписаний цілочисельний тип із шириною рівно 8, 16, 32 та 64 біта відповідно без бітів заповнення та використовуючи доповнення 2 для від'ємних значень (надається лише в тому випадку, якщо реалізація безпосередньо підтримує типу)? " Трохи не вистачає? Що це означає?
YSC

C ++ 11 базується на C99, а не на C11. Але це все одно не важливо
LF

Відповіді:


81

все ще переповнення цих типів невизначеною поведінкою?

Так. Відповідно до пункту 5/4 стандарту C ++ 11 (стосовно будь-якого виразу загалом):

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

Той факт, що представлення доповнення двох використовується для тих типів, що підписуються, не означає, що арифметика за модулем 2 ^ n використовується при обчисленні виразів цих типів.

Що стосується непідписаної арифметики, то, з іншого боку, Стандарт прямо вказує, що (пункт 3.9.1 / 4):

Беззнакові цілі числа, оголошені unsigned, повинні підкорятися законам арифметики за модулем 2 ^ n, де n - кількість бітів у поданні значень цього конкретного розміру цілого числа

Це означає, що результат непідписаної арифметичної операції завжди " математично визначений ", а результат завжди знаходиться в репрезентативному діапазоні; тому 5/4 не застосовується. Виноска 46 пояснює це:

46) Це означає, що беззнакова арифметика не переповнюється, оскільки результат, який не може бути представлений результуючим цілим беззнаковим типом, зменшується за модулем на число, яке на одне перевищує найбільше значення, яке може бути представлене отриманим цілим беззнаковим типом.


1
Цей параграф також означатиме, що переповнення без підпису є невизначеним, що ні.
Арчі

8
@Archie: Неправда, оскільки значення без знака визначаються за модулем діапазону без знака.
Гонки легкості на орбіті

3
@Archie: Я намагався пояснити, але в основному ти отримав відповідь від LightnessRacesinOrbit
Енді Проул

1
Насправді не має значення, чи визначено переповнення без підпису чи ні, якщо воно не може відбутися через модульний розрахунок ...
Аконкагуа

1
Є непідписані операції, результат яких не "математично визначений" - зокрема, ділення на нуль - тому, можливо, ваше формулювання не зовсім те, що ви мали на увазі у цьому реченні. ITYM, коли результат математично визначений , він також визначається в C ++.
Toby Speight

22

Тільки тому, що тип визначений для використання представлення доповнення 2s, це не означає, що арифметичне переповнення в цьому типі стає визначеним.

Невизначена поведінка підписаного арифметичного переповнення використовується для забезпечення оптимізації; наприклад, компілятор може припустити, що якщо a > bтоді a + 1 > bтакож; це не стосується арифметики без підпису, де слід було б здійснити другу перевірку через можливість, якою це a + 1може обернутися 0. Крім того, деякі платформи можуть генерувати сигнал пастки при арифметичному переповненні (див., Наприклад, http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html ); стандарт продовжує дозволяти це відбуватися.


5
Можливо, варто зауважити, що багато людей більше "хвилюються" щодо можливостей пасток, але припущення компілятора насправді є більш підступними (одна з причин, чому я хотів би, щоб існувала категорія між поведінкою, визначеною реалізацією, та невизначеною поведінкою - на відміну від поведінки, визначеної реалізацією що вимагає певних реалізацій, щоб робити щось послідовно задокументованим чином, я хотів би "поведінку, обмежену реалізацією", яка вимагала б, щоб реалізації вказували все, що може статися як наслідок чогось (специфікації можуть явно включати невизначену поведінку, але .. .
Supercat

3
... запрошення рекомендується бути більш конкретними, коли це практично). На апаратному забезпеченні, де два додаткові числа "обертаються" природним чином, немає розумної причини для коду, який хоче, щоб результат із загорнутим цілим числом виконував безліч інструкцій, які намагаються виконати без переповнення цілого числа обчислень, які апаратне забезпечення може зробити лише за одну-дві інструкції .
supercat

1
@supercat Насправді, код, який хоче завернутий результат, може (на доповнених 2 процесорах 2) просто перекинути операнди до відповідних непідписаних типів і виконати операцію (а потім повернути назад, отримавши значення, визначене реалізацією): це працює для додавання, віднімання та множення . Єдина проблема полягає в поділі, модулі та таких функціях, як abs. Для тих операцій, коли вона працює, вона не вимагає більше вказівок, ніж із підписаною артметикою.
Руслан

@Ruslan: У тих випадках, коли коду потрібен точно обернутий результат, приведення до непідписаного буде потворним, але не обов'язково генерує додатковий код. Більшою проблемою було б кодування, яке потребує швидкого виявлення "потенційно цікавих" кандидатів, який витратить більшу частину свого часу на відмову від нецікавих кандидатів. Якщо один надає компілятору свободу довільно зберігати або відкидати додаткову точність із підписаними цілими значеннями, але вимагає, щоб повернення до цілочисельного типу зрізало будь-яку таку точність, це дозволить більшість корисних оптимізацій, які можна було б досягти шляхом переповнення UB , ...
supercat

... але дозволить коду, який потребує точного обтікання, використовувати один привід, а не два (наприклад (int)(x+y)>z, порівняти обгорнутий результат), а також дозволить програмістам писати x+y>zв тих випадках, коли для коду прийнятно дати 0 або 1 у випадку переповнення за умови, що у нього немає інших побічних ефектів . Якщо або 0, або 1 буде настільки ж прийнятним результатом, дозволяючи програмісту писати це, а не будь-яке, (long)x+y>zабо (int)((unsigned)x+y)>zдозволятиме компіляторам вибирати, яка з останніх функцій була дешевшою в будь-якому даному контексті [кожна з них в деяких випадках буде дешевшою].
supercat

1

Я б поставив так.

Зі стандартної документації (стор. 4 та 5):

1.3.24 невизначена поведінка

поведінка, щодо якої цей міжнародний стандарт не вимагає жодних вимог

[Примітка: Невизначена поведінка може очікуватися, коли цей Міжнародний стандарт опускає будь-яке явне визначення поведінки або коли програма використовує помилкову конструкцію або помилкові дані. Допустима невизначена поведінка варіюється від ігнорування ситуації повністю з непередбачуваними результатами, до поведінки під час перекладу або виконання програми документально, характерним для середовища (з видачею діагностичного повідомлення або без нього), до припинення перекладу чи виконання (з видачею діагностичного повідомлення). Багато помилкових конструкцій програм не породжують невизначеної поведінки; їм потрібно поставити діагноз. - кінцева примітка]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.