引言编程习惯的培养需要一个长期的过程,需要不断的总结和积累,需要我们从意识上认识到它的重要性。良好的编程习惯对我们的能力很重要。改善也是一个巨大的帮助。以下是笔者在阅读本书时看到的一些良好的编程习惯的总结《专业嵌入式软件开发》,特此记录分享,判断失败而非成功以下为简化代码片段:if(physap_alarm_init()==RV_SUCC){if(trx_alarm_init()==RV_SUCC){if(bucket_init()==RV_SUCC){if(main_bhp_init()==RV_SUCC){/*正常代码*/}else{/*错误代码*/}}else{/*errorcode*/}}else{/*errorcode*/}}else{/*errorcode*/}可以看到上面的代码采用判断成功的策略后,if和else之间的代码嵌套非常混乱,看起来很不直观,代码也很难阅读,但是如果采用失败判断策略,代码看起来会简单很多。以下是采用故障判断策略后改进后的代码:}if(bucket_init()!=RV_SUCC){/*错误处理*/return;}if(main_bhp_init()!=RV_SUCC){/*错误处理*/return;}/*正常代码*/通过上面的代码,可以知道,修改后的代码去掉了if嵌套语句,大大提高了代码的可读性。需要注意的一点是,并不是所有情况下判断失败策略都比判断成功策略好,要视情况而定。使用sizeof减少内存操作错误。在写代码的时候,我们经常会涉及到使用memset函数将内存初始化为0,下面是几个错误示例://example1char*buf[MAX_LEN+1];memset(buf,0,MAX_LEN+1);上面代码的错误是忘记了buf是字符指针数组,而不是字符数组;继续看一段代码://example2#defineDIGEST_LEN17#defineDIGEST_MAX16chardigest[DIGEST_MAX];memset(digest,0,DIGEST_LEN);上面代码中的错误是宏的错误使用。虽然错误程度比较低,但是出错的可能性还是挺大的。最后一个例子://example3dll_node_t*p_node=malloc(sizeof(dll_node_t));if(p_node==0){return;}memset(p_node,0,sizeof(dll_t))上面代码的错误在于它分配的是dll_node_t类型的大小,但是下面的memset()使用了dll_t类型的大小,导致错误。为了减少错误,下面的代码使用了sizeof来避免内存操作错误。先看例程1的改进版:char*buf[MAX_LEN+1];memset(buf,0,sizeof(buf));接着看例子2的改进版代码:#defineDIGEST_LEN17#defineDIGEST_MAX16chardigest[DIGEST_MAX];memset(digest,0,sizeof(digest));例子3的改进版:dll_node_t*p_node=malloc(sizeof(*p_node));if(0==p_node){return;}memset(p_node,0,sizeof(*p_node))总结通过上面的代码,我们可以得出这么一个小结论。使用sizeof时,将需要初始化的目标变量名作为sizeof()的参数。可以简化为两条规则:当目标变量是数组时,使用sizeof(变量名)的格式获取内存的大小;当目标变量为指针时,使用sizeof(*指针变量名)的格式获取内存大小。上面的例子虽然使用了memset函数引入了sizeof,但是这个方法可以运行到任何需要获取变量内存大小的场合。屏蔽编程语言的特性数组是编程中经常用到的一个函数。以下是将会话ID保存在数组中的简化代码:#defineSESSION_ID_LEN_MAX256charg_SessionId[SESSION_ID_LEN_MAX];intsave_session_id(char*_session_id,int_length){if(_lengthSESSION_ID_LEN_MAX){returnERROR;}memcpy(g_SessionId,session_length),_length);g_SessionId[_length]='\0';returnSUCESS;}乍一看,你可能认为上面的代码没问题,但是在一个if语句中,实际上当_length等于SESSION_ID_LEN_MAX时,数组其实是越界的,所以上面的代码其实是有问题的,改的时候可能会改成下面的方式。if(_length=SESSION_ID_LEN_MAX){returnERROR;}这样改逻辑没有问题,但是代码变得不那么直观了,SESSION_ID_LEN_MAX字面意思是sessionID的最大长度,那么最大按理说长度应该是可以的,但是这里当_length等于SESSION_ID_LEN_MAX时,数组就溢出了。看代码看到>=的时候,基本上就需要停下来想一想为什么不能等于SESSION_ID_LEN_MAX。不能凭直觉理解,所以为了更好更顺利的理解代码,可以这样修改代码:#defineSESSION_ID_LEN_MIN1#defineSESSION_ID_LEN_MAX256/*这里修改*/charg_SessionId[SESSION_ID_LEN_MAX+1];intsave_session_id(char*_session_id,int_length){if(_lengthSESSION_ID_LEN_MAX){returnERROR;}memcpy(g_SessionId,session_id,_length);g_SessionId[_length]='\0';returnSUCESS;}通过上面的修改,也就是减小值SESSION_ID_LEN_MAX减一,那么此时可以将_length的值取为SESSION_ID_LEN_MAX,代码阅读起来更直观。正确使用goto语句我们在接触C语言编程的时候,大多被告知不要使用goto语句,以至于有时候看到goto语句就觉得程序很垃圾,但真实情况又是怎样的呢??当时并没有禁用goto语句,如果goto用得好,可以大大简化程序,提高程序的可读性和可维护性。下面是一段没有使用goto语句的代码,错误处理代码很多,代码如下:intqueue_init(queue**_pp_queue,int_size){pthread_mutexattrattr;queue*queue;queue=(queue_t*)malloc(sizeof(queue_t));if(0==queue){return-1;}*_pp_queue=queue;memset(queue,0,sizeof(*queue));queue->size_=_size;pthread_mutexattr_init(&attr);if(0!=pthread_mutex_init(&queue->mutex_,&attr)){pthread_mutexattr_destroy(&attr);free(queue);return-1;}queue->messages_=(void**)malloc(queue->size_*sizeof(void*));if(0==queue->messages_){pthread_mutexattr_destroy(&attr);free(queue);return-1;}if(0!=sem_init(&queue->sem_put_,0,queue->size)){free(queue->message_);pthread_mutexattr_destroy(&attr);free(queue);return-1;}pthread_mutexattr_destroy(&attr);return0;}通过上面的代码我们可以看出,在处理错误的时候很容易省略,代码看起来比较臃肿。下面是使用goto语句后的代码:intqueue_init(queue**_pp_queue,int_size){pthread_mutexattrattr;queue*queue;queue=(queue_t*)malloc(sizeof(queue_t));if(0==queue){return-1;}*_pp_queue=queue;memset(queue,0,sizeof(*queue));queue->size_=_size;pthread_mutexattr_init(&attr);if(0!=pthread_mutex_init(&queue->mutex_,&attr)){gotoerror;}queue->messages_=(void**)malloc(queue->size_*sizeof(void*));if(0==queue->messages_){gotoerror;}if(0!=sem_init(&queue->sem_put_,0,queue->size)){gotoerror1;}pthread_mutexattr_destroy(&attr);return0;error1:free(queue->messages_);error:pthread_mutexattr_destory(&attr);free(queue);return-1;}可以看到使用goto后代码的可读性时使用goto,还需要注意以下两个原则:不要滥用,不要让goto语句形成循环。goto语句的使用要排成一行,合理使用数组。在多任务编程环境中,部分任务的生命周期与整个程序的生命周期相同。它们在程序初始化时创建,然后运行直到程序结束。为此,我们称之为具有全局生命周期的任务。如果具有全局生命周期的任务需要内存资源,我们可以定义一个全局或静态数组而不是动态分配。Thefollowingistheuseofmalloctoinitializetheglobalvariableg_aaa_eap_str_buff代码:#defineMAX_AAA_SS_PORTS64#defineMAX_NUM_PADIUS_IDS(MAX_AAA_SS_PORTS*256)#defineMAX_EAP_MESSAGE_LEN4096staticchar**g_aaa_eap_str_buff;voidthread_authenticator(void*_arg){g_aaa_eap_str_buff=(char**)malloc(MAX_NUM_PADIUS_IDS);if(0==g_aaa_eap_str_buff){log_error("Failedtoallocatebufferforstoringeapstring");return;}for(inti=0;i