270 likes | 466 Views
C 语言编程培训. 软件部平台产品. 2003 年 7 月 7 日. 前 言. 疑问: C 语言还要培训吗? 回答: C 语言易学难精,功能强大,而且非常灵活,使用不慎,易造成灾难性后果。尤其在嵌入式系统,尤其强调软件的稳定性。. 提 纲. 1 、字符串的使用 2 、指针的使用 3 、数组和指针 4 、 switch case 的使用 5 、断言的使用 6 、 sizeof 的使用 7 、各种数值类型的边界值 8 、运算符优先级
E N D
C语言编程培训 软件部平台产品 2003年7月7日
前 言 疑问:C语言还要培训吗? 回答:C语言易学难精,功能强大,而且非常灵活,使用不慎,易造成灾难性后果。尤其在嵌入式系统,尤其强调软件的稳定性。
提 纲 1、字符串的使用 2、指针的使用 3、数组和指针 4、 switch case的使用 5、断言的使用 6、 sizeof 的使用 7、各种数值类型的边界值 8、运算符优先级 9、宏的使用 10、{ }的使用 11、资源的互斥 12、调用时是否回阻塞 13、动态内存的使用
(1)字符串的使用 关键点:字符串必须以‘\0’结尾。 案例1: sprintf(pDstStr, “%s”, pSrcStr); 或strcpy(pDstStr,pSrcStr) /* 当pSrcStr没有以‘\0’结尾时,结果…… */ 问题: (1)、strlen的返回值是多少?考虑下面的数组char szStr[] = {‘1’, ‘0’,’0’,’\0’,’a’,’\0’,’0’}。如果szStr没有初始化时呢? (2)、’\0’等于多少?‘0’==‘\0’ ???
(2)指针的使用 关键点:指针是一种数据类型,其值是内存地址。使用时指针,时刻注意内存地址位置 案例1: void change(char *p) { p = “xyz”;} char *pcStr = “abc”; change(pcStr); printf(“%s”, pcStr); /* 结果等于_______ */ 问题: (1)、指针占几个字节?char ***的意义?struct st1 **的意义? (2)、(*pstr).age == pstr->age ???
(3)数组和指针的使用 关键点:指针和数组是等价的。 案例1: int my_array[] = {1,23,17,4,-5,100}; int *ptr = my_array; int *ptr = &my_array[0]; 问题: (1)、char *p[ ] = {“BOOL”, “OPK”}的等价数组定义是什么?
(4)switch case的使用 关键点:一定有default分支,并在其中增加断言。 问题: (1)、为什么?
(5)断言的使用 关键点:正常情况下不可能出现的情况使用断言。 案例1: int gArray[4] = {1, 2}; int funA(int i) { assert(i < 0); return gArray[i]; } /* 错了,错在哪里了? */ 问题: (1)、什么是正常情况下不可能出现的情况? (2)、如何把断言和容错性结合起来?
(6)sizeof的使用 关键点:sizeof的值是在编译时决定的 问题: int gArray[4] = {1, 2}; int *ptr = (int*)malloc(30); void *pv = malloc(10); (1)、sizeof(gArray) = ?, sizeof(ptr) = ? (2)、sizeof(*ptr) = ?, sizeof(*pv) = ?
(7)各种数值类型的边界值 关键点:注意各种数据类型的最大和最小值 案例: unsigned short i = 0; …… if(i < 16 * 100* 10) {…} 问题: (1)、char和unsigned char的边界值?其他类型? (2)、函数参数尤其注意,为什么?
(8)运算符优先级 关键点:不同类型运算符混合使用,就用括号把它们隔离开来 案例: unsigned short i = 0; …… if(10 < 1 + i >> 3) {…} /* 是等于(1+i) >> 3 还是等于1 + (i >> 3) ?????*/
(9)宏的使用 关键点:宏的参数加();整个表达式加( );定义体中多条语句使用{ }。 案例: #define sum(a, b) a + b …… a = sum(1, 1 + 2); b = sum(1, 2) * 3; …. a = ???? b = ???? 问题: (1)、为什么宏的定义体中有多条语句时要用{ }。
(10){ }的使用 关键点:{ }表示语句块。if…else…分支使用{ } 案例: …… if ( CHECK_FLAG ( old->flags, XXX_WAIT_DELETE ) ) { if ( new == old ) assert( 0 ); xxx_xxx_delete( rn, old, safi ); } UNSET_FLAG ( old->flags, XXX_OLD_SEND ); …… /* 结果….. */ 问题: (1)、什么是语句块?
(11)考虑资源的互斥 关键点:多个任务访问同一数据,一定有互斥保护 提示: (1)、给其他模块提供函数接口时,尤其注意。
(12)调用函数时是否阻塞 关键点:提供和调用函数时,注意是否会阻塞 提示: (1)、调用其他模块提供的函数时,注意是否会阻塞。 (2)、提供函数接口给其他模块时,说明是否会阻塞。 (3)、是否会产生死锁。
(13)动态内存的使用 关键点:时刻提醒自己,动态内存是谁申请的,是多大,该谁释放,何时释放。 提示: (1)、释放一块内存时,确定没有其他分支和任务再使用该内存。 (2)、操作内存块(无论是否是动态的),时刻提醒自己,是否超过内存块 大小。
总 诀 关键点:编码时怀疑一切,出错也不能死机。 提示: (1)、完全不信任所有的外界输入,包括用户命令和报文。 (2)、对来自其他模块的输入保持怀疑。 (3)、每个环节都可能出现最坏情况。 (4)、任何一个环节出了问题时,可以放弃操作并报错,但决不能死机。
例 子 要求:实现利用单向链表实现一个队列的操作 struct node struct queue_head struct queue_head *head = NULL; { { int data; int count; struct node *next; struct node *first, *last; }; }; 假设: head已经分配内存,而且初始化了。
no good void queue_add( int data) { struct node *node; node = (struct node*)malloc(sizeof(struct node*)); node->data = data; node->next = NULL; head->last->next = node; head->last = node; head->count++; return 0; } good int queue_in( int data) { struct node *node = NULL; if( NULL == head) { assert(0); return –1; } if( (head->last) || (head->last->next)) { assert(0); return –1; } node = (struct node*)malloc(sizeof(struct node*)); if(NULL == node) { assert(0); return –1; } node->data = data; node->next = NULL; head->last->next = node; head->last = node; head->count++; return 0; } 改进之处 (1)、函数名 (2)、缺少空行 (3)、缺少代码保护,没有考虑异常处理。 (4)、缺少函数头部的说明,缺少注释
good int queue_count( ) { if(( NULL == head) || (0 > head->count)) { assert(0); return –1; } return head->count; } no good int queue_count( ) { return head->count; }
good int queue_out(int *data) { if(NULL == data) { assert(0); return –1; } if((NULL == head) || (0 > head->count)) { assert(0); return –1; } if(0 == head->count) { return –1; } if(NULL == head->first) { assert(0); return -1 } *data = head->first->data; free(head->first) ; head->first = head->first->next; head->count--; return 0; } no good int queue_delete( ) { return head->first->data; } no good void queue_delete(int *data) { if(head->count == 0) { return; } *data = head->first->data; head->first = head->first->next; head->count--; return; }