C++中的”未定义的行为”

2.1 位运算

位运算的运算对象是整数类型的,并且把运算对象看成是一个二进制位的集合。运算对象可以是带符号也可以是无符号。如果是带符号且值为负,那么位运算如何处理运算对象的符号位依赖于机器。而且此时的左移操作可能会改变符号位的值。因此会产生未定义的行为。

关于符号位如何处理C++标准没有明确规定,所以强烈建议将位运算用于处理无符号类型。因此,在使用位运算的过程中,因尽量将对象声明为无符号的,如:unsigned char、unsigned int 等。

2.2 求值顺序、运算符执行顺序、表达式

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

比如int i=f1()*f2();该表达式的乘法运算符没有指定运算的顺序,所以,这里是f1()先执行还是f2()先执行是未定义的、未知的,f1()和f2()谁先执行取决于编译器如何处理。

2.3 避免无法预知和依赖于实现环境的行为

无法预知的行为源于编译器无须检测的错误。即使代码编译通过了,如果程序执行了一条未定义的表达式,仍有可能产生错误。

2.4类型转换、赋值

当赋值给带符号类型一个超过它表示范围的值时,结果是未定义的,程序可能继续工作,可能崩溃也可能生成数据垃圾。

2.5 函数的参数列表

实参与形参存在一一对应的关系,但是并没有规定实参的求值顺序,编译器可以任意可行的顺序对参数求值。这个与连乘的性质有些类似。连乘也没有规定求值得顺序,因此在使用的过程中,需要注意求值顺序是否对结果有影响,不要想当然的认为参数列表是从左到右或者从右到左的对表达式进行求值。

2.6 函数返回值

当函数具有非空的返回值时,如果函数的每一条执行路径中,有一条或多条路径可能没有相应的return语句,则可能会产生未定义的行为。当然,这种情况有可能编译器可以检测到并且给出相应的提示。但如果编译器未检测到,则该函数在运行时的行为将是未定义的。

2.7 返回局部对象的引用或指针

函数执行完之后,它所占用的存储空间也被释放掉。所以,函数终止意味着局部变量的引用将指向不再有效的内存区域。例如下面的例子:

Int & getid()
{
         int i=0;
         i=10;
         if(i>5)
         {
                   return I;
         }
         else
         {
                   return -1;
         }
}

试图使用上面这个函数的返回值将引发未定义的行为。

上面是一个返回局部对象的引用的例子。同样的,返回局部对象的指针也是错误。因为函数结束后,局部对象所占的空间被释放,指针将指向一个不存在的对象。

原文链接: https://www.cnblogs.com/xiongmao-cpp/p/5243308.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/229569

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 下午2:22
下一篇 2023年2月13日 下午2:22

相关推荐