▎a+=b和a=a+b 真的完全等价吗?▎
在C语言中,相信 a+=b 和 a = a+b大家都有写过,那你有没有思考过这二者究竟是不是完全等价的呢?
其实这个问题的难点就在a和b的数据类型上,要分两种情况:
1、对于同样类型的a,b来说
两个式子执行的结果确实没有什么区别。但是从编译的角度来看,a+=b;执行的时候效率高。
2、对于不同类型的a,b来说
不同类型的两个变量在进行运算的时候,我们经常说到的是类型的转换问题。这里,请记住一点:运算过程中,低精度的类型向高精度类型转换。
在上面的代码中,如果使用+=,b会直接转换成 char,如果使用a+b,a首先转换成int,最后赋值的时候再转换成char。
因此,总的来说,a=a+b;和a+=b;并不是任何时候都等价,要分情况视之,原因就在数据类型转换这里,希望大家以后对这两者慎重使用。
▎a[i] = i++ 到底对不对?▎
编程中有时会遇到一些有歧义的表达式,比如 a[i] = i++ 。 那么 a[i] = i++ 到底对不对呢?
首先请看如下代码:
对于这个表达式中 a[i] = i++,子表达式i++有一个副作用,它会改变i的值,由于i在同一表达式中会被引用,因此这样会导致未定义的行为。因为无法判定该引用(该公式中的左边的a[i]中)是新值还是旧值。
不同的编译器在解释此类行为的时候会有不同的理解,比如下面三个编译器(dev c++ 、 codeblocks、vs2019 )对于上述的代码就有不同的理解。
从上面的运行的截图可以观察到相同的一段代码,dev c++和codeblocks的执行结果是相同的,但是vs2019和它们却并不相同。
对于此类行为,尽管有些文献中认为这类表达式的行为是不确定的,但是c标准却强烈声明它是未定义的。
未定义行为的其他示例包括访问超出其边界的数组, 解除引用空指针, 在生命终结后访问对象 或写作 据称聪明的表达 喜欢i++ + ++i。
未定义的行为还有两个不那么危险的兄弟,不确定的行为和实现定义的行为。
那么实现定义的行为、不确定的行为、未定义的行为这三者的区别在哪里呢?
首先这三种情况都代表了c语言标准中没有明确要求某个特定构造或使用它的程序必须完成的事情的领域。c语言定义中的这种松散性是传统的,但是这种规定方式是经过深思熟虑的,这种定义方式允许作者:
1、选择某些构造可以按照“硬件完成的方式”生成高效的代码。
2、忽略某些太难准确定义、并且可能在良好书写的程序中没什么实际用处的边界构造。
▎对于这3种“标准中没有准确定义的行为”的定义如下:
1、实现定义的行为
抽象机的某些方面和操作在本国际标准中描述为实现定义(例如,sizeof(int))。这些构成了抽象机器的参数。每个实施应包括描述其在这些方面的特征和行为的文件。
2、不确定的行为
抽象机的某些其他方面和操作在本国际标准中描述为不明(例如,评估函数参数的顺序)。在可能的情况下,C语言国际标准定义了一组允许的行为。这些定义了抽象机器的非确定性方面。
3、未定义的行为
任何事情都有可能发生,标准对此没有任何要求,程序可能编译失败、运行错误(直接崩溃或者生成错误的结果)或者幸运的如程序员所愿。
既然标准对编译器没有进行任何要求,那么编译器就可以做出任何可能的行为。在程序中忍受未定义的想法是极其危险的,未定义行为比你想象的还要未定义。
如果大家想书写可移植代码,那么上述的三种行为都是需要极力避免的。因此我们在编写代码时最好避免 a[i] = i++ 这种C语言未定义的写法。
— END —
领取专属 10元无门槛券
私享最新 技术干货