首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Undefined behavior

如果语言的某些规则被违反,整个程序就会变得毫无意义。

解释

C++标准精确地定义了可观察行为对于不属于以下类之一的每个C++程序:

  • 畸形-程序有语法错误或可诊断的语义错误。一个符合标准的C++编译器需要发出诊断,即使它定义了一个语言扩展,该扩展为这样的代码%28指定了意义,比如使用可变长度数组%29。标准文本使用,,,不得,和畸形以表明这些要求。
  • 不需要诊断-程序有语义错误,一般情况下不能诊断。违反ODR或仅在链接时间%29可检测到的其他错误。如果执行这样的程序,则该行为是未定义的。
  • 实现-定义的行为-程序的行为因实现而异,符合的实现必须记录每种行为的效果。例如,std::size_t或字节中的位数,或std::bad_alloc::what实现定义行为的子集是特定地区行为,这取决于提供的实现。现场...
  • 未指定行为-程序的行为因实现而异,不需要符合的实现来记录每种行为的效果。例如,评价顺序,是否相同字符串文字数组分配开销的大小等等。每个未指定的行为都会产生一组有效的结果之一。
  • 未定义行为-对该方案的行为没有任何限制。未定义行为的例子有:数组边界外的内存访问、带符号整数溢出、空指针取消引用、对同一个标量的修改。不止一次在没有序列点的表达式中,通过不同类型的指针访问对象,等等。编译器不需要诊断未定义的行为%28,尽管许多简单的情况被诊断为%29,并且编译的程序不需要做任何有意义的事情。

UB与优化

由于正确的C++程序不存在未定义的行为,因此,当实际具有UB的程序在启用优化的情况下编译时,编译器可能会产生意外的结果:

例如,

符号溢出

二次

代码语言:javascript
复制
int foo(int x) {
    return x+1 > x; // either true or UB due to signed overflow
}

二次

可以编译为%28演示29%。

二次

代码语言:javascript
复制
foo(int):
        movl    $1, %eax
        ret

二次

出界

二次

代码语言:javascript
复制
int table[4] = {};
bool exists_in_table(int v)
{
    // return true in one of the first 4 iterations or UB due to out-of-bounds access
    for (int i = 0; i <= 4; i++) {
        if (table[i] == v) return true;
    }
    return false;
}

二次

可以编译为%28演示29%。

二次

代码语言:javascript
复制
exists_in_table(int):
        movl    $1, %eax
        ret

二次

未初始化标量

二次

代码语言:javascript
复制
std::size_t f(int x)
{
    std::size_t a;
    if(x) // either x nonzero or UB
        a = 42;
    return a; 
}

二次

可以编译为%28演示29%。

二次

代码语言:javascript
复制
f(int):
        mov     eax, 42
        ret

二次

在早期版本的GCC上观察到了所显示的输出。

二次

代码语言:javascript
复制
bool p; // uninitialized local variable
if(p) // UB access to uninitialized scalar
    std::puts("p is true");
if(!p) // UB access to uninitialized scalar
    std::puts("p is false");

二次

可能的产出:

二次

代码语言:javascript
复制
p is true
p is false

二次

访问传递给realloc的指针

选择clang来观察所显示的输出。

二次

代码语言:javascript
复制
#include <iostream>
#include <cstdlib>
int main() {
    int *p = (int*)std::malloc(sizeof(int));
    int *q = (int*)std::realloc(p, sizeof(int));
    *p = 1; // UB access to a pointer that was passed to realloc
    *q = 2;
    if (p == q) // UB access to a pointer that was passed to realloc
        std::cout << *p << *q << '\n';
}

二次

可能的产出:

二次

代码语言:javascript
复制
12

二次

无副作用的无限循环

选择clang来观察所显示的输出。

二次

代码语言:javascript
复制
#include <iostream>
 
int fermat() {
  const int MAX = 1000;
  int a=1,b=1,c=1;
  // Endless loop with no side effects is UB
  while (1) {
    if (((a*a*a) == ((b*b*b)+(c*c*c)))) return 1;
    a++;
    if (a>MAX) { a=1; b++; }
    if (b>MAX) { b=1; c++; }
    if (c>MAX) { c=1;}
  }
  return 0;
}
 
int main() {
  if (fermat())
    std::cout << "Fermat's Last Theorem has been disproved.\n";
  else
    std::cout << "Fermat's Last Theorem has not been disproved.\n";
}

二次

可能的产出:

二次

代码语言:javascript
复制
Fermat's Last Theorem has been disproved.

二次

外部链接

代码语言:txt
复制
 ? cppreference.com

在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com