Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1494060
  • 博文数量: 100
  • 博客积分: 667
  • 博客等级: 上士
  • 技术积分: 1619
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-27 15:59
个人简介

一沙一世界 一树一菩提

文章分类

全部博文(100)

文章存档

2021年(8)

2020年(16)

2019年(8)

2017年(3)

2016年(11)

2015年(17)

2014年(9)

2013年(4)

2012年(19)

2011年(1)

2009年(4)

分类: C/C++

2021-09-16 16:06:08

         现在,貌似使用c语言进行软件编程开发的人越来越少了啊。周围大部分同事都C++和python了。但是估计应该不会消失吧。我自己工作很多年一直都用C开发,以为挺不错。但是近几天无意翻了翻《C安全编码》,突然发现原来我对C一直都是一知半解啊。平时相当然认为的常规做法其实一直都是有问题的,下面就是一些记录。没有考虑到的地方,欢迎大家提出来。


一 字符究竟是什么类型


         你可能理所当然的认为是char,或者unsigned char 或signed char。我也这么认为,其实我们都错了。

     1.1 凡是带get语义的字符获得函数,如getc、fgetc、getchar....返回值都是int类型;

     1.2 sizeof('a')的值是4,也就是int类型的大小,也就是说char a = ‘a’,执行sizeof(a)和sizeof('a')并不相等。



二 realloc和alloca函数使用


         这两个都是申请内存空间的函数,可能这两个函数使用的并不多,我们一般使用malloc和free就够了。但是这2个函数需要拿出来说下,你稍微不小心就会出错,导致coredump。


2.1  realloc

         原型是void* realloc(void* p, size_t size),这个函数用于空间扩展,并且扩展后的空间还必须包括原来空间的内容。p是前面通过malloc、calloc或realloc返回的指针。除了原来的内容保留下来,其余空间未初始化,而原来的空间指针p释放。这个函数主要有以下几种情况:

2.1.1 如果realloc返回空指针,那么旧的p值不变化,就当没有调用过realloc函数;

2.1.2 如果p为空,则realloc和malloc(size)相同;

2.1.3 如果size为0,realloc相当于free(p),但是不建议这么做,如下代码段:


(此处)折叠或打开

  1. char* p2;
  2. char* p = malloc(100);
  3. ...
  4. if((p2 = realloc(p, nsize)) == NULL)
  5. {
  6.     if(p)
  7.         free(p)
  8.     p = NULL;
  9.     return NULL;
  10. }
  11. = p2;
似乎没问题,仔细看下,如果nsize为0的话会如何?p会多次释放。改为如下就好了:


点击(此处)折叠或打开

  1. char* p2;
  2. char* p = malloc(100);
  3. ...
  4. if((nsize == 0) || ((p2 = realloc(p, nsize)) == NULL))
  5. {
  6.  free(p)
  7.  p = NULL;
  8.  return NULL;
  9. }
  10. p = p2
其实,最好的办法是永远不申请0字节长度的空间。


2.2 alloca

        这个函数申请的空间在栈上。不必手动释放。


三 无符号数据类型计算永远不会溢出


         现代计算机存储数值都是以补码形式存储,如4位无符号整形的取值:0、1、2、3、4、5、6、7、8、9、10、11、12、13、14、15,最大数值是15,再加1回滚到0,而最小数值是0,,再减一会回滚到15,永远不会出现负数。所以下面循环永远不会退出:


点击(此处)折叠或打开

  1. for(unsigned i = n; i >= 0; i--)


四 求绝对值


        补码形式存储4位有符号数举例子:0、1、2、3、4、5、6、7、-8、-7、-6、-5、-4、-3、-2、-1,这个也会回滚,你的注意点要几种的7和-8这两位身上,即四位有符号数最大是7,再加1就是最大的负数,四位有符号数最小是-8,再减1就是最大的7。除此之外,你还有没有发现什么,那就是正负数不对称。这要紧吗?接着看:

点击(此处)折叠或打开
  1. #define abs(n)    ((n) < 0 ? -(n) : (n))
也就是说4位有符号数,最小负数是-8,对-8取绝对值是8,但是遗憾的是4位有符号数不能表示8这个数值,你说有没有问题吧。


五  char型数值


        如果你想要定义某数值类型为char,建议你不要这么定义,如果非要定义不可,那就定义成unsigned char或signed char。char类型做数值运算,究竟是按照unsigned char还是signed char来计算,取决于编译器,也就是说你这个char具体是什么数值取决于环境。如:

点击(此处)折叠或打开

  1. char a = 200;
  2. int b = 1000;
  3. printf("b/a = %d\n", b/a)
在我电脑上输出是-17,为毛啊?我的电脑把char型数值计算是按照signed char型来操作的,signed char是无法存储200这个数值的,200和位模式和-56的位模式相同,我的电脑就是1000/(-56)这样计算的。

先到这,有新的易出错的知识点再补。



阅读(68) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~