编写安全的代码——小心有符号数的右移操作
2014-03-12 18:30
197 查看
在嵌入式开发当中,做数据运算(乘、除)等表达式时,移位操作是工程师们的最爱。但是也要非常谨慎,比如有符号数和无符号数、变量的取值范围。
来看看这样一段小代码:
这是一个朋友写的程序,他呢,看觉得num /= 2,想起课程上讲过,整数右移一位,就等于除于二,并且右移操作比除法运算要高效的多。于是将 num /=2 改为了 num = num>>1。
于是代码变为
输入正数测试时,没问题,ok !
当输入负数时说他的程序陷入了死循环:
[cheng@localhost test]$ ./a.out
-5
-5
-2
-1
-1
-1
。。。。。。
-1
那么到底是什么原因呢?我当时也没找出问题的根源,可是回来仔细推敲一番,我以十六进制的方式打印了下结果,果然。生无符号数与有符号数在作怪!右移一位就等于除以2,但是这里需要加一个条件,这里指的是正数。而对于有符号整数,且其值为负数时,在C99标准中对于其右移操作的结果的规定是implementation-defined.运行到最后,对于 -1(十六进制0xffffffff)(二进制1111 1111 1111 1111 1111 1111 1111 1111)不管你怎么移位,一直都是这个数,问题就是这!所以进入了死循环。
要注意的是:为了明确传入的参数,你最好加入特定类型 。比如你要传入的是有符号的整形。你就这样定义:signed int 等价于 int.要是你想传入的是无符号的整形数呢,你就定义成:unsigned int 。通过这样明确限定,就算是误传的话,编译器也会强制转换
来看看这样一段小代码:
#include <stdlib.h> #include <stdio.h> static void divide_by_two(int num) { while (num){ printf("%d\n", num); num /= 2; } } int main(void) { int num; scanf("%d", &num); divide_by_two(num); return 0; }
这是一个朋友写的程序,他呢,看觉得num /= 2,想起课程上讲过,整数右移一位,就等于除于二,并且右移操作比除法运算要高效的多。于是将 num /=2 改为了 num = num>>1。
于是代码变为
#include <stdlib.h> #include <stdio.h> static void divide_by_two(int num) { while (num){ printf("%d\n", num); num = num>>1; } } int main(void) { int num; scanf("%d", &num); divide_by_two(num); return 0; }
输入正数测试时,没问题,ok !
当输入负数时说他的程序陷入了死循环:
[cheng@localhost test]$ ./a.out
-5
-5
-2
-1
-1
-1
。。。。。。
-1
那么到底是什么原因呢?我当时也没找出问题的根源,可是回来仔细推敲一番,我以十六进制的方式打印了下结果,果然。生无符号数与有符号数在作怪!右移一位就等于除以2,但是这里需要加一个条件,这里指的是正数。而对于有符号整数,且其值为负数时,在C99标准中对于其右移操作的结果的规定是implementation-defined.运行到最后,对于 -1(十六进制0xffffffff)(二进制1111 1111 1111 1111 1111 1111 1111 1111)不管你怎么移位,一直都是这个数,问题就是这!所以进入了死循环。
要注意的是:为了明确传入的参数,你最好加入特定类型 。比如你要传入的是有符号的整形。你就这样定义:signed int 等价于 int.要是你想传入的是无符号的整形数呢,你就定义成:unsigned int 。通过这样明确限定,就算是误传的话,编译器也会强制转换
相关文章推荐
- 编写安全代码——小心有符号数的右移操作
- 编写安全代码——小心有符号数的右移操作(转载)
- 编写安全代码——小心有符号数的右移操作
- 编写安全代码——小心有符号数的右移操作
- 编写安全代码:小心使用浮点数
- 编写安全代码:小心volatile的原子性误解
- 编写安全代码:小心volatile的原子性误解
- 编写安全代码:小心volatile的原子性误解
- 编写安全代码:小心使用浮点数
- 编写安全代码:有符号数和无符号数的移位区别
- 编写安全代码:有符号数和无符号数的移位区别---右移
- 编写安全代码:小心使用浮点数
- 编写高质量代码改善C#程序的157个建议[泛型集合、选择集合、集合的安全]
- 内存管理---编写安全的代码的一些技巧 C++
- 编写安全代码:再论整数类型转换
- 写高质量OC代码52建议总结:32.编写“异常安全代码”时留意内存管理问题
- 不安全的代码: 教你“随心所欲”地在内存中操作Java的类和对象(4)
- 检查代码是否存在整数操作安全漏洞
- 编写异常安全的代码永远不会亏本
- 编写安全的Symbian C++游戏代码