全部学习汇总: https://github.com/GreyZhang/misra_c_hacking
12.1, 规则12.1(咨询):在表达式中,应该对C语言的运算符优先级规则有一定的限制。
关于这一条规则,有两点需要注意:1,合理使用括号,括号并不是越多越好; 2,有时候,括号的位置会让运算的结果发生变化。在上面的也给出了一个可以参考的例子。
通常,在学习阶段可能老师讲解的时候会考察大家对于结合性以及优先级的处理。但是我觉得这个并不是编程的核心点所在,如果以工程实施为目的这样的时间不用花很多。不过,这样会带来一定的不足,那就是对这个知识点的认识不足。怎么办呢?合理使用括号就是一个很好的选择。
12.2, 在标准允许的任何评估顺序下,表达式的值应相同。
关于这一条规则,里面介绍的相关的知识点还是很多的。针对几个比较值得注意的做一个梳理。
1. 求值顺序问题,单纯使用括号也是无法全部解决的。例子很容易找,其实多个条件表达式的与或非判断就是一个很好的例子。
2. 涉及到++或者--这样的操作,尽量做一个拆分。针对这一条,我个人采用了更加激进的方式:这个表达式我只在for循环中用,而且用法很单一。其他时候所有的操作全都用 += 做一个变相的替代。
3. 如果有了第二条中自己规定的编码规范要求,其实上面提到的作为函数的参数操作中可能出现的问题也就不存在了。
4. 如果通过函数指针调用函数,则不应依赖于函数指示符和函数参数的求值顺序。
5. 尽量不要在表达式中使用过多的函数调用,尤其是函数中可能存在对同一个变量修改情况的时候。
6. 多级赋值也不要用。看到这一条,有一个问题值得回忆一下。之前看linux内核的时候,早期版本的内核代码中其实看得出来求值等有些事从右往左计算的,而我用比较新的工具以及系统测试的时候则不同。这里的这个规则要求,看起来也有类似的问题考虑。不同的工具在行为设计上可能有不同的定义,尤其是标准中没有定义的行为在实现的时候可能会有不同的效果。
7. volatile的读取可能也意味着数值的一次更新,这个在嵌入式的设计中尤为需要注意。
8. 浮点数的表达在不同数值范围内精度不同,因此多个数值相加的时候不同的顺序可能会导致不同的结果。
12.3, sizeof只能够应用于类型或者对象的处理。
12.4,逻辑&&或| |运算符的右操作数不应包含副作用。
针对这一条的处理,可以通过一条规则来要求:与或等操作符右边的表达式不应该影响当前的变量或者状态信息的内容。
12.5, 与以及或的操作表达式中操作符都应该是初级表达式,如果是复杂的表达式则应该考虑使用括号等让这个表达式本身的结果表述更加精确。
12.6, 这一条其实是对布尔量的使用场景做了一个要求。只能够用于这样的逻辑判断,不能够用于其他的运算。
12.7, 位运算只能够用于无符号数的处理。
12.8,左移操作的操作数只能够在0~n-1之间,其中n是数据的bit数。
12.9,一元减号不能够用于基础类型为无符号类型的表达式。这个很容易理解,一元减号其实本来就是一个求负值的过程,既然求解负值,那么数据本身必须先有正负属性才可以。
12.10,不要用逗号表达式。这个,我还真在工作中看到有的工程师很喜欢用。
12.11,无符号的求值不应该导致溢出回滚。这个是一个建议性的,我觉得从习惯上来说用的也不少。尤其是嵌入式的控制软件设计会有很多可以回滚处理的计数器用以表征不同状态,其实还是有一些应用存在的。
12.12, 不要对浮点数进行位处理。这一条也是很容易理解的,但是前提是对浮点数的表达有一定的认识。浮点数的表达不是线性精度,因此位运算在不同范围中会有不同的效果。
12.13,++以及--不要在一个表达式中与其他的操作符混用。我觉得实现这一条规则还是很简单的,方法还是用我前面提到的。除了for循环等循环结构外,这样的操作符号我直接不用,而是用+=或者-=来取代。这样,直接不会出现这样的表达式混用。
这一个章节学到的东西还是很多的,也看到了通过这些规则来解决开发中问题的一些可能性。看起来,这个规范还是很有必要推广落实的,很多年轻的工程师并意识不到这其中的价值所在。