美文网首页C/C++/Linux
未定义行为(Undefined behavior)

未定义行为(Undefined behavior)

作者: ninedreams | 来源:发表于2020-08-17 22:35 被阅读0次

    Implementation-defined、Unspecified和Undefined

    • Implementation-defined
      C标准没有明确规定char是有符号的还是无符号的,但是要求编译器必须对此
      做出明确规定,并写在编译器的文档中
    • Unspecified
      往往有几种可选的处理方式,C标准没有明确规定按哪种方式处理,编译器可以自己决定,并且也不必写在编译器的文档中,这样即使用同一个编译器的不同版本来编译也可能得到不同的结果,因为编译器没有在文档中明确写它会怎么处理,那么不同版本的编译器就可以选择不同的处理方
      式,比如下一章我们会讲到一个函数调用的各个实参表达式按什
      么顺序求值是Unspecified的
    • Undefined
      这种的情况则是完全不确定的,C标准没规定怎么处理,编
      译器很可能也没规定,甚至也没做出错处理,有很多Undefined的
      情况是编译器是检查不出来的,最终会导致运行时错误,比如数
      组访问越界就是Undefined的。

    什么是未定义行为

    未定义行为(Undefined Behavior)是指语言标准未做规定的行为。同时,标准也从没要求编译器判断未定义行为,所以这些行为由编译器自行处理,在不同的编译器可能会产生不同的结果,又或者如果程序调用未定义的行为,可能会成功编译,甚至一开始运行时没有错误,只会在另一个系统上,甚至是在另一个日期运行失败。当一个未定义行为的实例发生时,正如语言标准所说,“什么事情都可能发生”,也许什么都没有发生。

    未定义的结果
    1、当我们赋给带符号类型一个超出它表示范围的值时,结果是未定义的。
    signed char c2 = 256; // c2的值是未定义的

    2、函数体之内定义的变量:未初始化(uninitialized),其值undefined。

    3、算术表达式有可能产生未定义的结果

    数学性质本身:除数为0
    计算机的特点:溢出;很多系统在编译和运行时都不报出溢出错误,像其他未定义的行为一样,溢出的结果是不可预知的。

    C++的未定义行为

    未定义行为,无法预估Runtime会发生什么(unpredictable:normal、crashing、incorrect results)。

    1、解引用空指针、非法迭代器或者尾后迭代器都是未定义行为

    2、访问一个无效数组索引,下标越界

    3、当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果是未定义的。实际执行时通常发生的是对象的derived成员没有被销毁。

    4、在两个异常同时存在的情况下,程序若不是结束执行就是导致未定义行为。

    5、释放一个非new分配的内存,或者将相同的指针值释放多次,其行为是未定义的。

    6、string s(s2,pos2); // s是string s2从下标pos2开始的字符拷贝,如果pos2>s2.size(),构造函数的行为未定义

    7、试图比较两个无关地址是未定义行为

    8、对于那些没有指定执行顺序的运算符来说,如果表达式指向并修改了同一个对象,将会引发错误并产生未定义的行为。

    int i=0;
    
    cout<< i << " " << ++i << endl; // 未定义
    
    // 编译器可能先求++i的值,再求i的值;也可能先求i的值,再求++i的值。注意与print函数的区别。
    
    *beg = toupper(*beg++); // 未定义
    

    9、对有符号数进行左移操作可能会改变符号位的值,因此是一种未定义的行为。移位运算符右侧的运算对象一定不能为负,而且值必须严格小于结果的位数,否则就会产生未定义的行为。

    10、使用static_cast将void*转换成其他类型指针,必须确保转换后所得的类型就是指针所指的类型。类型一旦不符,将产生未定义行为。

    double d;
    void* p = &d;
    double *dp = static_cast<double*>(p);
    

    11、const_cast只能改变运算对象的底层const,如果对象本身是一个常量,使用const_cast执行写操作就会产生未定义行为。

    12、不要使用get初始化另一个智能指针或为智能指针赋值,否则将会产生两个独立的shared_ptr指向相同的内存,这将产生未定义行为。

    13、delete[] p;如果忘记[],其行为是未定义的。 删除单一对象的指针加[],其行为也是未定义的。

    相关文章

      网友评论

        本文标题:未定义行为(Undefined behavior)

        本文链接:https://www.haomeiwen.com/subject/qbffnctx.html