【问题标题】:What exactly do "IB" and "UB" mean?“IB”和“UB”到底是什么意思?
【发布时间】:2011-02-15 12:58:56
【问题描述】:

我见过多次使用“IB”和“UB”这两个术语,尤其是在 C++ 上下文中。我试过用谷歌搜索它们,但显然这些两个字母的组合很有用。 :P

所以,我问你......当他们被说成是坏事时,他们是什么意思?

【问题讨论】:

  • 如果您决定回滚其他人的编辑,请确保您的拼写、标点和语法完美无缺。回滚对原始文本进行实质性改进的编辑是没有意义的。

标签: c++ terminology definition


【解决方案1】:

【讨论】:

  • 所以 IB 是...集成晴雨表? :P
  • @Frustrated:不确定 IB。不得不谷歌它。 :P
【解决方案2】:

IB:实现定义的行为。该标准将其留给特定的编译器/平台来定义精确的行为,但要求对其进行定义。

使用实现定义的行为可能很有用,但会降低代码的可移植性。

UB:未定义行为。该标准没有指定调用未定义行为的程序应如何行为。也被称为“鼻恶魔”,因为理论上它可以让恶魔飞出你的鼻子。

使用未定义的行为几乎总是一个坏主意。即使它有时似乎有效,对环境、编译器或平台的任何更改都可能会随机破坏您的代码。

【讨论】:

  • 由于在 C++ 中使用了未定义的行为,我仍在等待恶魔从某人的鼻子中飞出。我想当第一个编译器完全符合新的 C++ 标准时就会发生这种情况。
  • @OregonGhost:我想你是对的。我曾多次看到独角兽发生过这种情况,但从未见过恶魔。
  • @OregonGhost - 标准没有规定恶魔应该有多少个角。
  • 好吧,中断服务是因为 2GB 内存转储正在写入磁盘,这会大大减慢速度,恐怕这还不够愚蠢:(
  • @Michael Burr:我更喜欢“着火”。这显然是灾难性的,并且至少有一种模糊的似是而非的感觉(计算机硬件有时会起火,诚然,在您阅读此线程的任何系统的情况下,由于硬件而不是软件故障的原因)。
【解决方案3】:
  • IB:是实现定义的行为 - 编译器必须记录它的作用。对负值执行>> 操作就是一个示例。

  • UB:未定义的行为 - 编译器可以做任何事情,包括简单地崩溃或给出不可预测的结果。取消引用空指针属于这一类,但也包括超出数组对象边界的指针算术等更微妙的事情。

另一个相关术语是“未指定行为”。这介于实现定义和未定义的行为之间。对于未指定的行为,编译器必须根据标准做一些事情,但标准给它的确切选择取决于编译器,不需要定义(甚至是一致的)。诸如子表达式的评估顺序之类的事情属于这一类。编译器可以按照它喜欢的任何顺序执行这些操作,并且可以在不同的构建中甚至在同一构建的不同运行中以不同的方式执行这些操作(不太可能,但允许)。

【讨论】:

    【解决方案4】:

    实现定义的行为和未定义的行为

    C++ 标准对各种构造的影响非常具体,尤其是您应该始终注意这些类别的问题

    • 未定义的行为意味着绝对不提供任何保证。该代码可以工作,或者它可能会着火你的硬盘或make demons fly out your nose。就 C++ 语言而言,任何事情都可能发生。实际上,这通常意味着您有一个不可恢复的错误。如果发生这种情况,您将无法真正信任有关您的应用程序的任何内容(因为这种未定义行为的影响之一可能就是弄乱了应用程序其余部分使用的内存)。它不需要保持一致,因此运行程序两次可能会产生不同的结果。这可能取决于月相、您所穿衬衫的颜色或其他任何因素。

    • 未指定的行为意味着程序必须做一些理智和一致的事情,但不需要记录

    • 实现定义的行为类似于未指定的行为,但也必须由编译器编写者记录。这方面的一个例子是reinterpret_cast 的结果。 通常,它只是改变指针的类型,不修改地址,但映射实际上是实现定义的,所以编译器可以映射到完全不同的地址,只要它记录了这个选择。另一个例子是 int 的大小。 C++ 标准不关心它是 2、4 还是 8 字节,但它必须由编译器记录

    但所有这些的共同点是最好避免使用它们。如果可能,坚持 100% 由 C++ 标准本身指定的行为。这样,您就可以保证可移植性。

    您通常还必须依赖一些实现定义的行为。这可能是不可避免的,但您仍然应该注意它,并注意您所依赖的东西可能会在不同的编译器之间发生变化。

    另一方面,应该始终避免未定义的行为。一般来说,您应该假设它使您的程序以一种或另一种方式爆炸。

    【讨论】:

    • UB 应该避免如果你关心可移植性。特定的实现可以定义特定的未定义行为会发生什么,并且在某些情况下(尤其是设备驱动程序和较小的嵌入式系统)您需要使用这些东西。
    • @Jerry: 不,应该避免 UB如果它完全未定义。如果平台/实现/运行时/编译器提供了进一步的保证,那么您可以依赖行为并失去可移植性。但是,它不再是未定义的了……但是,大多数时候,您没有这样的保证,而 undefined 只是未定义的,应该不惜一切代价避免。
    • "consistent" 可能是对未指定行为的误导性描述。它必须与操作的一般上下文一致,例如,如果表达式具有“未指定的值”,则结果必须一个值,如果存储它,则存储的值此后必须比较相等对自己,等等。但是未指定的结果不需要随着时间的推移保持一致(如果再次运行,相同的输入输出相同的输出),甚至是确定性的。
    • “不再完全未定义” - 它与 标准 完全一样未定义,而 UB 是标准未定义的简写含义。在您的示例中,它由实现定义。就此而言,您可以依赖标准实现未定义的行为,如果您已检查目标代码并且不打算再次重新编译;-)
    • “此后必须与自身比较”。嗯,除非它是一个 NaN。无论如何,它必须具有其类型所需的任何行为。
    【解决方案5】:

    简短版:

    实现定义的行为 (IB): 正确编程但不确定*

    未定义行为 (UB): 编程错误(即 错误!)

    *) 就语言标准而言“不确定”,当然在任何固定平台上都是确定的。

    【讨论】:

    • 如果标准表明一个动作调用了实现定义的行为,则需要实现来指定由该动作产生的一致行为。不幸的是,没有哪类行为需要实现来指定可能的后果,但不需要任何特定的后果始终如一地发生。
    猜你喜欢
    • 2017-08-07
    • 2017-07-20
    • 2014-09-23
    • 2014-07-25
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多