Що саме означають “IB” та “UB”?


110

Я бачив терміни "IB" та "UB", які вживаються декілька разів, особливо в контексті C ++. Я спробував їх погуглити, але, мабуть, ці двобуквені комбінації бачать багато користі. : P

Отже, я запитую вас ... що вони означають, коли кажуть, що вони погані?


5
Якщо ви вирішили відмовитись від інших прав, переконайтеся, що ваш правопис, пунктуація та граматика ідеальні. Відкат правок, які суттєво покращують оригінальний текст, є безглуздим.
Роберт Харві

Відповіді:


139

IB: Поведінка, визначена реалізацією. Стандарт залишає його за певним компілятором / платформою для визначення точної поведінки, але вимагає, щоб це було визначено.

Використання визначеної реалізацією поведінки може бути корисним, але робить ваш код менш портативним.

УБ: Не визначена поведінка. Стандарт не визначає, як повинна поводитися програма, яка викликає невизначене поведінку. Також відомий як «носові демони», оскільки теоретично це може змусити демонів вилетіти з вашого носа.

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


11
Я все ще чекаю демона, який вилітає з когось із носа через те, що в C ++ не визначена поведінка. Я думаю, це станеться, коли перші компілятори повністю відповідають новому стандарту C ++.
OregonGhost

4
@OregonGhost: Я думаю, ти маєш рацію. Я бачив, як це відбувається з однорогами пару разів, але ніколи не з демонами.
Томас

33
@OregonGhost - стандарт не вказує, скільки рогів повинен мати демон.
DVK

5
@Michael Burr: Я віддаю перевагу "загорітися". Це, очевидно, катастрофічно, і він має, принаймні, невиразну атмосферу правдоподібності (комп'ютерне обладнання іноді загоряється, правда, з апаратних причин, а не з ладу програмного забезпечення у випадку будь-якої системи, на якій ви читали б цю тему).
Стів Джессоп

1
Смішно, як ніхто, відповідаючи на це питання, не має меншої репутації, ніж 30 к.

19

Поведінка, визначена реалізацією та Не визначена поведінка

Стандарт C ++ дуже специфічний щодо впливу різних конструкцій, і, зокрема, ви завжди повинні бути в курсі цих категорій проблем :

  • Невизначена поведінка означає, що гарантій абсолютно не дано. Код може спрацювати, або він може підпалити ваш жорсткий привід або змусити демонів вилетіти з вашого носа . Що стосується мови C ++, то може статися абсолютно все. На практиці це, як правило, означає, що у вас непоправна помилка. Якщо це трапиться, ви не можете дійсно довіряти чомусь своєму додатку (тому що одним із наслідків цього невизначеного поведінки може бути просто зіпсувати пам'ять, яку використовує решта вашого додатка). Це не потрібно, щоб бути послідовним, тому запуск програми двічі може дати різні результати. Це може залежати від фаз місяця, кольору сорочки, яку ви носите, або абсолютно нічого іншого.

  • Довільні означає поведінку , що програма повинна робити що - то SANE і послідовним, але це не обов'язково документувати це.

  • Поведінка, визначена реалізацією, є подібною до не визначеної, але її також слід документувати авторами-упорядниками. Прикладом цього є результат а reinterpret_cast. Зазвичай він просто змінює тип вказівника, не змінюючи адресу, але відображення насправді визначено реалізацією, тому компілятор міг би відобразити зовсім іншу адресу, доки він задокументував цей вибір. Інший приклад - розмір int. Стандарт C ++ не має значення, якщо він становить 2, 4 або 8 байт, але він повинен бути задокументований компілятором

Але загальним для всього цього є те, що їх найкраще уникати. Коли це можливо, дотримуйтесь поведінки, яка на 100% визначена самим стандартом C ++. Таким чином, ви гарантуєте портативність.

Вам часто доводиться покладатися і на певну поведінку, визначену реалізацією. Це може бути неминучим, але все ж слід звернути на це увагу і пам’ятати, що ви покладаєтесь на те, що може змінюватися між різними компіляторами.

З іншого боку, невизначеної поведінки завжди слід уникати. Загалом, ви просто повинні припустити, що це змушує вашу програму вибухати так чи інакше.


1
УБ слід уникати, якщо ви дбаєте про переносимість . Конкретна реалізація може визначити, що відбувається для конкретної невизначеної поведінки, і в деяких випадках (особливо драйвери пристроїв та менші вбудовані системи) потрібно використовувати ці речі.
Джеррі Труну

3
@Jerry: Ні, UB слід уникати, якщо він повністю не визначений . Якщо платформа / імплементація / час виконання / компілятор дає додаткові гарантії, то ви можете розраховувати на свою поведінку і втрачати портативність. Але тоді це вже не так не визначено ... Однак, більшість часу у вас немає таких гарантій, а невизначене просто невизначене, і його слід уникати будь-якою ціною.
jalf

"послідовний" може бути оманливим описом не визначеної поведінки. Він повинен відповідати загальному контексту операції, наприклад, якщо вираз має "невизначене значення", то результат повинен бути значенням, якщо ви зберігаєте його, то збережене значення повинне згодом порівнюватись із рівним собі тощо. Але не визначені результати не повинні бути узгодженими протягом часу (той самий вихід на той же вхід, якщо ви запустили його знову), або навіть детермінований.
Стів Джессоп

"вже не так не визначено" - це точно так само, як визначено стандартом , а UB - це коротке значення, що не визначене стандартом. У вашому прикладі це визначено реалізацією. З цього приводу ви можете покластися на поведінку, яка не визначена стандартом або реалізацією, якщо ви перевірили код об'єкта і не плануєте повторно перекомпілювати ;-)
Стів Джессоп

"повинен після цього порівнювати себе рівним". Хм, якщо це не NaN. У будь-якому випадку вона повинна мати будь-яку поведінку, яка вимагається від її типу.
Стів Джессоп

8
  • IB: це визначена поведінкою поведінка - компілятор повинен документувати, що він робить. >>Приклад виконання операції з негативним значенням.

  • UB: невизначена поведінка - компілятор може робити все, що завгодно, включаючи просто збій або надання непередбачуваних результатів. Перенаправлення нульового вказівника підпадає під цю категорію, але також тонкі речі, такі як арифметика вказівника, що виходить за межі об'єкта масиву.

Інший пов'язаний термін - «невказана поведінка». Це свого роду між визначеними реалізацією та невизначеними формами поведінки. для не визначеної поведінки компілятор повинен робити щось відповідно до стандарту, але саме той вибір, який стандарт надає, залежить від компілятора і не повинен визначатися (або навіть послідовно). Такі речі, як порядок оцінювання суб-виразів, належать до цієї категорії. Компілятор може виконувати їх у будь-якому порядку, який йому подобається, і міг би це робити по-різному в різних збірках або навіть у різних прогонах однієї збірки (навряд чи, але дозволено).


4

Коротка версія:

Поведінка, визначена реалізацією (ІБ): Правильно запрограмована, але невизначена *

Не визначена поведінка (UB): Невірно запрограмований (тобто помилка !)

*) "невизначений", що стосується мовного стандарту, він, звичайно, визначатиметься на будь-якій фіксованій платформі.


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

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