[MISRA C 2004](三)防范表达式的失控

1.1      表达式的求值顺序

1.1.1   表达式的值必须在任何求值顺序下保持一致

考虑下面两段程序。

程序一:执行以下程序,从串口依次输入2 4 ,变量result 将等于多少?

/* 注:uart_GetChar是从串口接收一个ASCII字符的函数 */

uint8_t result;

result = uart_GetChar() – uart_GetChar();

程序二:执行以下程序,变量result将等于多少?

uint8_t result;

uint8_t temp = 2;

result = temp+++--temp;

 

由于C语言标准规定的只是运算符的结合顺序,而对于二元运算符的求值顺序未作定义,“对于二元操作符,要先对两个操作数进行求值之后(但未指定求值顺序)再进行运算”。因此上述两段程序的最终结果取决于编译器特性。

如果使用的编译器总是从左向右解析表达式,则结果是:

程序一:result = ‘2’ – ‘4’ = 0x32 – 0x34 = 0xFE;

程序二:result = 2 + 2 = 4;

如果使用的编译器总是从右向左解析表达式,则结果是:

程序一:result = ‘4’ – ‘2’ = 0x34 – 0x32 = 0x02;

程序二:result = 1 + 1 = 2;

1.1.2   应该减少表达式对运算符优先级的依赖性

考虑下面一段程序:

if (STATRegister & BUSYMask = = 0)

{

       do_something ;

}

 

该程序的本意是读状态寄存器( STATRegister ) 的值,如果其BUSY位是0 (即被掩码BUSYMask 选中) ,则做某些操作。但是,由于判等运算符“= = ”的优先级高于位与操作符“&,实际的判断表达式变成了“( STATReg2ister & (BUSYMask = = 0) ) ! = 0。此时应该加入括号“() ”以保证判断表达式的正确性:

if ( (STA TRegister & BUSYMask ) = = 0)

{

       do_something ;

}

 

1.2      表达式的副作用

1.2.1   不允许将sizeof运算符作用于有副作用的表达式上

考虑下面一段程序:

uint32_t i;

uint16_t j;

j = sizeof(i = 1234);

 

本意是先将1234 赋给i ,再把i 所占用的空间大小传给j 。可是由于sizeof 运算符只针对数据类型进行操作, 所以“j = sizeof (i = 1234) ”实际上被替换成“j = sizeof(int32_t) ”。故表达式“i = 1234的操作不会进行,这就带来了可能的隐患。正确的做法是将最后一句替换成:

i = 1234 ;

j = sizeof (i) ;

1.2.2   逻辑运算(&&||)的右操作数不允许包含副作用

C 语言的表达式中,部分代码可能不被求值。如果这些代码具有副作用,就会产生一些隐患。典型的例子出现在逻辑运算中:

if (istrue | | do_something_with_side_effects () )

{

do_something ;

}

如果istrue 0 ,编译器认为表达式的值已经确定为真,从而不再进行后面的求值,于是有副作用的操作被忽略,影响了后继操作。

 

1.2.3   逻辑运算符的操作数必须是一个主表达式(:这里主表达式包括标识符、常量和括号括起来的表达式)

1.2.4   逻辑运算符( & &| | !) 的操作数必须为一个有效的布尔值,布尔值表达式不允许进行逻辑运算以外的操作(:这是为了防止误用)

1.2.5   不允许对有符号数进行位操作(: 这是为了防止结果的不确定性)

1.2.6   移位操作的右操作数只能在0 和操作数的位数减1 之间(:移位操作的右操作数就是移位的位数,比如一个8 位的无符号整数,允许移位的位数范围是07 ,这是为了防止未定义的操作)

1.2.7   不允许无符号性的表达式进行一元负运算符(:同规则12. 8 )

1.2.8   不允许使用逗号表达式(:这是为了防止阅读混乱,另外,逗号表达式也可以用其他等价形式替代)

1.2.9   不允许对浮点型值进行位操作(:这是为了防止不同标准产生的差异性)

1.2.10 不允许在同一个表达式中混合使用+ + - - (:这是为了防止阅读混乱,并防止出现歧义)

转载于:https://www.cnblogs.com/mathrom/archive/2008/11/17/1335286.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值