Chinaunix首页 | 论坛 | 博客
  • 博客访问: 316819
  • 博文数量: 57
  • 博客积分: 146
  • 博客等级: 入伍新兵
  • 技术积分: 769
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-29 14:57
文章分类
文章存档

2014年(39)

2013年(13)

2012年(5)

我的朋友

分类: C/C++

2014-06-18 15:52:42

1.使用括号确保表达式执行顺序:

表达式:x与1相与后判断是否等于0.
错误表达式:

点击(此处)折叠或打开

  1. x & 1 == 0
因为==操作符的优先级高于&,表达式会先进行(1==0)操作,最后进行(x&0)操作。

正确表示:

点击(此处)折叠或打开

  1. (x & 1) == 0

C语言操作符优先级列表:Primary Expression Operators优先级最高,Unary Operators其次,依次类推。


2.错误使用sizeof(指向某类型的指针)来判断某类型大小:

点击(此处)折叠或打开

  1. double *d_array;
  2. size_t num_elems;
  3. /* ... */
  4. if (num_elems > SIZE_MAX/sizeof(d_array)){
  5.     /* handle error condition */
  6. }
  7. else {
  8.     d_array = malloc(sizeof(d_array) * num_elems);
  9. }
在32bit的系统中,sizeof(double)等于8,而sizeof(指向double类型的指针)等于4.

正确:

点击(此处)折叠或打开

  1. double *d_array;
  2. size_t num_elems;
  3. /* ... */
  4. if (num_elems > SIZE_MAX/sizeof(*d_array)){
  5.        /* handle error condition */
  6. }
  7. else {
  8.     d_array = malloc(sizeof(*d_array) * num_elems);
  9. }
在32bit系统中,sizeof(*d_array)等于8。

3.在逻辑AND和逻辑OR运算符(&&,| |)中,第二个表达式不应有副作用

错误
代码:

点击(此处)折叠或打开

  1. int i;
  2. int max;
  3. if ( (i >= 0 && (i++) <= max) ) {
  4.     /* code */
  5. }
(i++) <= max)可能是(i <= max)也可能是((i+1)<=max),由编译器决定。

正确:

点击(此处)折叠或打开

  1. int i;
  2. int max;
  3. if ( (i >= 0 && (i + 1) <= max) ) {
  4.     i++;
  5.    /* code */
  6. }
4.结构体各个成员的sizeof()大小之和,不一定等于结构体sizeof()大小。为保证结构体内存对齐(32bit系统为4字节对齐,需要结构体填充(structure padding)。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. struct buffer {
  4.     size_t size;
  5.     char buffer[50];
  6. };

  7. int main(void)
  8. {
  9.     struct buffer a;
  10.     printf("sizeof() : %d, sum of sizeof() : %d\n", sizeof(a), sizeof(a.size)+sizeof(a.buffer));
  11.     return 0;
  12. }

5.结构体之间的比较不要进行逐字节比较,采用逐结构体成员比较。因为存在结构体填充,其填充的字节数和内容是在执行时定义。若尝试逐字节比较会导致错误结果。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>

  4. struct buffer {
  5.     size_t size;
  6.     char buffer[50];
  7. };

  8. unsigned int buf_compare(struct buffer *s1, struct buffer *s2) {
  9.     if (!memcmp(s1, s2, sizeof(struct buffer))) {
  10.         return 1;
  11.     }
  12.     return 0;
  13. }


  14. unsigned int member_compare(struct buffer *s1, struct buffer *s2) {
  15.     if ((s1->size == s2->size) && (!memcmp(s1->buffer, s2->buffer, sizeof(s1->buffer)))){
  16.         return 1;
  17.     }
  18.     return 0;
  19. }

  20. int main(void)
  21. {
  22.     struct buffer a, b;
  23.     a.size = 0x01;
  24.     memset(a.buffer, 0x00, sizeof(a.buffer));
  25.     b.size = 0x01;
  26.     memset(b.buffer, 0x00, sizeof(b.buffer));
  27.     if (0x01 == buf_compare(&a, &b)){
  28.         printf("buf match!\n");
  29.     }else{
  30.         printf("buf not match!\n");
  31.     }

  32.     if (0x01 == member_compare(&a, &b)){
  33.         printf("member match!\n");
  34.     }else{
  35.         printf("member not match!\n");
  36.     }

  37.     return 0;
  38. }

6.不能修改const对象

错误:

点击(此处)折叠或打开

  1. void remove_spaces(char const *str, size_t slen) {
  2.     char *p = (char*)str;
  3.     size_t i;
  4.     for (i = 0; i < slen && str[i]; i++) {
  5.         if (str[i] != ' ') *p++ = str[i];
  6.     }
  7.     *p = '\0';
  8. }
函数remove_spaces取消字符串str中的空格,但是str为定义为char const *str,其值不能进行修改。

正确:

点击(此处)折叠或打开

  1. void remove_spaces(char *str, size_t slen) {
  2.         char *p = (char*)str;
  3.         size_t i;
  4.         for (i = 0; i < slen && str[i]; i++) {
  5.             if (str[i] != ' ') *p++ = str[i];
  6.         }
  7.         *p = '\0';
  8.     }

7.sizeof()的操作数不应包含副作用。具有副作用的操作数不会被执行或计算。

点击(此处)折叠或打开

  1. int a = 14;
  2. int b = sizeof(a++)
b初始化后,a还是等于14.sizeof()中的a++没有执行。
正确:

点击(此处)折叠或打开

  1. int a = 14;
  2. int b = sizeof(a);
  3. a++

8.谨慎使用NULL和0特别关于指针。
一个值为0整型常量表达式此类表达式强制转换为void *类型被称为空指针常量如果一个空指针常量转换成一个指针类型后得到的指针称为空指针不等于指向任何对象函数的指针


在编译阶段,常量0在指针上下文中被转换成空指针。也就是,在进行初始化,分配或比较时,一边是变量或表达式指针类型时,编译器会把另一边的常量0转换成具有正确类型的空指针值。例如下面代码:

点击(此处)折叠或打开

  1. char *p = 0;
  2. if(p != 0)
然而,一个传递给函数的参数不一定识别为一个指针上下文,编译器也不能把一个未修饰的0作为空指针。例如:

点击(此处)折叠或打开

  1. execl("/bin/sh", "sh", "-c", "ls", 0)
正确表示:

点击(此处)折叠或打开

  1. execl("/bin/sh", "sh", "-c", "ls", (char *)0)
建议如果是与指针相关最好使用NULL(NULL是专门用于这种情况),它会更容易检查使用不当的指针。
最好使用:

点击(此处)折叠或打开

  1. execl("/bin/sh", "sh", "-c", "ls", (char *)NULL)

9.确保指针运算正确使用

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <string.h>

  3. struct buffer{
  4.     int a;
  5.     char str[50];
  6. };

  7. int main()
  8. {
  9.     char s[] = "hello world!";

  10.     struct buffer buf;
  11.     buf.a = 0x04;
  12.     memset(buf.str, 0, sizeof(buf.str));

  13.     /* 错误, &buf+sizeof(buf.a)等于加上sizeof(struct buffer)*sizeof(buf.a)的偏移*/
  14.     memcpy(&buf+sizeof(buf.a), s, strlen(s));
  15.     printf("&buf's offset : %d\n", (char *)(&buf+sizeof(buf.a))-(char *)&buf);

  16.     /* correct */
  17.     memcpy(((char *)&buf+sizeof(buf.a)), s, strlen(s));
  18.     printf("(char *)&buf's offset : %d\n", (char *)&buf+sizeof(buf.a)-(char *)&buf);

  19.     return 0;
  20. }

10.使用sizeof来确定一个类型或变量的大小
不要硬编码一个类型的大小到代码中因为对齐填充基本类型因系统不同大小不同(例如32位与64位指针),大多数类型的大小发生变化在不同编译器之间,即使是版本相同的编译器。
错误:

点击(此处)折叠或打开

  1. int *p = (int *)calloc(1, 4)

正确:

点击(此处)折叠或打开

  1. int *p = (int *)calloc(1, sizeof(int)

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