位置:51电子网 » 技术资料 » 其它综合

跨越数据类型的重重陷阱

发布时间:2007/8/30 0:00:00 访问次数:476

作者:清华大学 张乐平 邵贝贝


数据类型是编程语言中最基本的构成元素,但却是最易被忽略的一环,程序员愿意把几乎100%的精力都花在算法研究、程序流控制等大环节上,却很少在数据类型问题上反复斟酌。
 
细节决定成败,一个螺丝钉的失误可能导致一个飞行器的毁灭,一个数据类型的错误同样可以让庞大的软件系统崩溃。


MISRA—c中关于数据类型的规则主要分为两个方面。一是数据类型相关的编程风格;二是不同数据类型之间的转换,后者是重点。这里介绍MISRA_C关于数据类型的部分规则,更多的规则请参考《MISRA-C:2OO4)》一书。


下文中凡是未加特殊说明的都是强制(required)规则.个别推荐(advisory)规则加了“推荐”标识。


在展开论述之前,先看两个问题,读者可以带着疑问阅读完本章内容。


问题1:执行以下程序,result_8的值是多少?
ulnt8_t porI=0x5a;
uint8一t resuh_8;
result_8=(~port)>>4;
/*注:uint8_t表示8位无符号整型*/


问题2:执行以下程序,d的值是多少?
uintl6_t a=10;
uin|16_t b=6553l;
uint32_t c=0;
uint32_t d;
d=a+b+c;
/*注:uintl6_t表示16位无符号整型,uint32_t表示32位无符号整型*/ 


1 数据类型相关的编程风格
规则6.3(推荐):必须用typedef显式标识出各数据
类型的长度和符号特性,避免直接使用标准数据类型。
例如,一个32位的整数系统,可定义如下:
typedef char chat_t;
typedef sigrled char int8_t;
typedef signed short intl6_t;
typedef signed int int32_t;
typedef signed long int64_t;
typedef unsitgned chat uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned 1ong uint64_t;


之所以用intl6_t和uint32_t等代替signed short和unsigned int等标准数据类型标识符,是由于不同的编译器对标准数据类型的长度定义是不一样的。比如说一个16位系统,很可能就把short和int都定义成16位,long定义成32位,这与上文32位系统中标准数据类型的长度就不一致。


用intl6_t和uint_32等标识符来定义变量,一方面增加了程序的可读性,使得程序员本人或其他读者都能对程序中数据的具体信息胸有成竹;


另一方面也有助于程序在不同系统之间的移植,节省开发时间,减少隐患。规则7 1:不得使用八进制常数(O除外)或八进制转义符。
思考如下数组:
code[1]=109;
code[2]=100;
code[3]=O52
code[4]=O71;
/*注:八进制常数须在最高位加O*/


code[3]的实际值是42(十进制),code[4]的实际值是57(十进制);但估计很多读者会把code[3]认成是52(十进制),code[4]认成是7l(十进制)。


八进制数在C程序中使用的频率远小于十进制数和十六进制数,为了保证程序的可读性和安全性,程序员不允许使用八进制数以及八进制转义符。 


2  数据类型转换
如果程序员对数据类型的转换有很清晰的认识,并且在必要的地方做了正确的显式强制转换,那程序是安全的。但有时由于程序员的疏忽,或者是过于相信编译器的“智慧”程度,导致表达式中有很多隐式转换(即没有显式地强制转换),而这些隐式数据类型转换很可能就构成致命的漏洞。MISRA—C中数据类型转换规则的着眼点,即是避免有漏洞的隐式数据转换。


在介绍MISRA—C关于数据类型转换的部分规则之前,先介绍整型操作数的“平衡(balance)”原则。所谓整型操作数“平衡”原则,即对于隐式表达式,编译器会按照既定规则对操作数进行位数扩充,其中int和unsiglled int在整型表达式“平衡”过程中占重要地位。


下面分析一个简单的隐式整型表达式c=a+b(假设a的存储位数不大于b的存储位数),编译器是这样来处理这个表达式的:


如果b是短整型(即位数少于int,比如char、short等)或者整型(int或unsigned int),那a也是短整型或者整型,执行“+”运算之前,a和b都将被扩充为整型(int或者unsigned int),然后相加的结果赋给c(如果c不是int或者unsigned int类型,则这个赋值操作也会包含隐式的扩充或截断操作)。


如果b是长整型(存储位数多于int),则a会被扩充为与b相当的长整型,再执行“+”运算,所得结果赋给c(可能包含隐式的扩充或截断操作)。


绝大部分的操作符用于整型运算的时候,都遵循上述“平衡”原则,比如:算术操作符、位操作符和关系运算符。


但逻辑操作符不遵循上述“平衡”原则。此外左移(<<)和右移(>>)运算符也不遵循“平衡”原则,只和移位操作符左边的整型操作数相关。假设一个8位的短整型变量值为Oxf5(十六进制),则右移4位所得结

作者:清华大学 张乐平 邵贝贝


数据类型是编程语言中最基本的构成元素,但却是最易被忽略的一环,程序员愿意把几乎100%的精力都花在算法研究、程序流控制等大环节上,却很少在数据类型问题上反复斟酌。
 
细节决定成败,一个螺丝钉的失误可能导致一个飞行器的毁灭,一个数据类型的错误同样可以让庞大的软件系统崩溃。


MISRA—c中关于数据类型的规则主要分为两个方面。一是数据类型相关的编程风格;二是不同数据类型之间的转换,后者是重点。这里介绍MISRA_C关于数据类型的部分规则,更多的规则请参考《MISRA-C:2OO4)》一书。


下文中凡是未加特殊说明的都是强制(required)规则.个别推荐(advisory)规则加了“推荐”标识。


在展开论述之前,先看两个问题,读者可以带着疑问阅读完本章内容。


问题1:执行以下程序,result_8的值是多少?
ulnt8_t porI=0x5a;
uint8一t resuh_8;
result_8=(~port)>>4;
/*注:uint8_t表示8位无符号整型*/


问题2:执行以下程序,d的值是多少?
uintl6_t a=10;
uin|16_t b=6553l;
uint32_t c=0;
uint32_t d;
d=a+b+c;
/*注:uintl6_t表示16位无符号整型,uint32_t表示32位无符号整型*/ 


1 数据类型相关的编程风格
规则6.3(推荐):必须用typedef显式标识出各数据
类型的长度和符号特性,避免直接使用标准数据类型。
例如,一个32位的整数系统,可定义如下:
typedef char chat_t;
typedef sigrled char int8_t;
typedef signed short intl6_t;
typedef signed int int32_t;
typedef signed long int64_t;
typedef unsitgned chat uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned 1ong uint64_t;


之所以用intl6_t和uint32_t等代替signed short和unsigned int等标准数据类型标识符,是由于不同的编译器对标准数据类型的长度定义是不一样的。比如说一个16位系统,很可能就把short和int都定义成16位,long定义成32位,这与上文32位系统中标准数据类型的长度就不一致。


用intl6_t和uint_32等标识符来定义变量,一方面增加了程序的可读性,使得程序员本人或其他读者都能对程序中数据的具体信息胸有成竹;


另一方面也有助于程序在不同系统之间的移植,节省开发时间,减少隐患。规则7 1:不得使用八进制常数(O除外)或八进制转义符。
思考如下数组:
code[1]=109;
code[2]=100;
code[3]=O52
code[4]=O71;
/*注:八进制常数须在最高位加O*/


code[3]的实际值是42(十进制),code[4]的实际值是57(十进制);但估计很多读者会把code[3]认成是52(十进制),code[4]认成是7l(十进制)。


八进制数在C程序中使用的频率远小于十进制数和十六进制数,为了保证程序的可读性和安全性,程序员不允许使用八进制数以及八进制转义符。 


2  数据类型转换
如果程序员对数据类型的转换有很清晰的认识,并且在必要的地方做了正确的显式强制转换,那程序是安全的。但有时由于程序员的疏忽,或者是过于相信编译器的“智慧”程度,导致表达式中有很多隐式转换(即没有显式地强制转换),而这些隐式数据类型转换很可能就构成致命的漏洞。MISRA—C中数据类型转换规则的着眼点,即是避免有漏洞的隐式数据转换。


在介绍MISRA—C关于数据类型转换的部分规则之前,先介绍整型操作数的“平衡(balance)”原则。所谓整型操作数“平衡”原则,即对于隐式表达式,编译器会按照既定规则对操作数进行位数扩充,其中int和unsiglled int在整型表达式“平衡”过程中占重要地位。


下面分析一个简单的隐式整型表达式c=a+b(假设a的存储位数不大于b的存储位数),编译器是这样来处理这个表达式的:


如果b是短整型(即位数少于int,比如char、short等)或者整型(int或unsigned int),那a也是短整型或者整型,执行“+”运算之前,a和b都将被扩充为整型(int或者unsigned int),然后相加的结果赋给c(如果c不是int或者unsigned int类型,则这个赋值操作也会包含隐式的扩充或截断操作)。


如果b是长整型(存储位数多于int),则a会被扩充为与b相当的长整型,再执行“+”运算,所得结果赋给c(可能包含隐式的扩充或截断操作)。


绝大部分的操作符用于整型运算的时候,都遵循上述“平衡”原则,比如:算术操作符、位操作符和关系运算符。


但逻辑操作符不遵循上述“平衡”原则。此外左移(<<)和右移(>>)运算符也不遵循“平衡”原则,只和移位操作符左边的整型操作数相关。假设一个8位的短整型变量值为Oxf5(十六进制),则右移4位所得结

相关IC型号

热门点击

 

推荐技术资料

罗盘误差及补偿
    造成罗盘误差的主要因素有传感器误差、其他磁材料干扰等。... [详细]
版权所有:51dzw.COM
深圳服务热线:13692101218  13751165337
粤ICP备09112631号-6(miitbeian.gov.cn)
公网安备44030402000607
深圳市碧威特网络技术有限公司
付款方式


 复制成功!