我已经看过多次使用术语“IB”和“UB”,特别是在C ++的上下文中。我试过用谷歌搜索它们,但显然这些两个字母的组合看起来很有用。 :P
所以,我问你......当他们被说成是一件坏事时,他们的意思是什么?
答案 0 :(得分:125)
IB:实现定义的行为。标准将其留给特定的编译器/平台来定义精确的行为,但要求定义它。
使用实现定义的行为可能很有用,但会降低代码的可移植性。
UB:未定义的行为。该标准未指定调用未定义行为的程序应如何运行。也被称为“鼻子恶魔”,因为理论上它可以让恶魔飞出你的鼻子。
使用未定义的行为几乎总是一个坏主意。即使它似乎有时工作,对环境,编译器或平台的任何更改都可能会随机破坏您的代码。
答案 1 :(得分:17)
实现定义的行为和未定义的行为
C ++标准对各种结构的效果非常具体,特别是你应该始终了解 trouble 的这些类别:
未定义的行为意味着绝对没有任何保证。代码可以工作,或者它可以激活你的硬盘或make demons fly out your nose。就C ++语言而言,绝对可能发生任何事情。实际上,这通常意味着您有一个不可恢复的错误。如果发生这种情况,您无法真正信任任何关于您的应用程序(因为这种未定义行为的影响之一可能只是弄乱了应用程序其余部分使用的内存)。它不需要保持一致,因此两次运行程序可能会产生不同的结果。这可能取决于月亮的阶段,你穿着的衬衫的颜色,或者其他任何东西。
未指定的行为意味着程序必须做一些合理且一致的事情,但不需要记录。
实现定义的行为类似于未指定的行为,但也必须由编译器编写者记录。一个例子是reinterpret_cast
的结果。 通常,它只是改变指针的类型,而不修改地址,但映射实际上是实现定义的,因此编译器可以映射到完全不同的地址,只要它记录了这个选择。另一个例子是int的大小。 C ++标准不关心它是2,4或8字节,但必须由编译器记录
但所有这些的共同点是他们最好避免。如果可能,坚持使用C ++标准本身100%指定的行为。这样,您就可以保证可移植性。
您通常还必须依赖某些实现定义的行为。这可能是不可避免的,但您仍应注意它,并注意您依赖于可能在不同编译器之间发生变化的内容。
另一方面,未定义的行为应该避免始终。一般来说,你应该假设它使你的程序以某种方式爆炸。
答案 2 :(得分:8)
IB:是实现定义的行为 - 编译器必须记录它的作用。对负值执行>>
操作就是一个例子。
UB:未定义的行为 - 编译器可以做任何事情,包括简单地崩溃或给出不可预测的结果。取消引用空指针属于这个类别,但也会出现像指针算术这样的更微妙的东西,它们超出了数组对象的范围。
另一个相关术语是“未指明的行为”。这是实现定义和未定义行为之间的一种。对于未指定的行为,编译器必须根据标准执行某些操作,但是标准给出的确切选择取决于编译器,无需定义(甚至不一致)。类似于子表达式的评估顺序属于这一类。编译器可以按照自己喜欢的顺序执行这些操作,并且可以在不同的版本中执行,也可以在同一版本的不同运行中执行(不太可能,但允许)。
答案 3 :(得分:4)
答案 4 :(得分:4)
简短版本:
实施定义的行为(IB):正确编程但不确定*
未定义的行为(UB):编程错误(即 bug !)
*)就语言标准而言,“不确定”,它当然可以在任何固定平台上确定。