【文档说明】C语言编程基础概要课件.ppt,共(86)页,1.124 MB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-44474.html
以下为本文档部分文字说明:
HUAWEITECHNOLOGIESCO.,LTD.www.huawei.comHuaweiConfidentialSecurityLevel:华为技术有限公司C语言编程基础内部公开HUAWEITECHNOLOGIESCO.,
LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIE
SCO.,LTD.HuaweiConfidential前言提高我司产品竞争力,研发要在以下几个方面下功夫:提高规划水平,把握正确的方向(战略)提高设计水平,搭建合理的系统(战术)提高编码水平,开发稳定的代码(单兵作战技能)HUAWEITECH
NOLOGIESCO.,LTD.HuaweiConfidential前言我们为什么要进行培训?最好的医术是预防真正的难问题往往是低级错误引起的我们的编码水平不容乐观C是程序员的语言HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential前言要提高编
码水平,每个开发人员要做到:勤学苦练,提高编程技能前车之鉴,后世之师,不犯同样的错误;坚持代码Review、PC-LINT检查和单元测试;总而言之,就是少犯错误,尽早发现错误HUAWEITECHNOLO
GIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLO
GIESCO.,LTD.HuaweiConfidential基础篇之简单就是美If(a&&b||c|d==e&f)这个表达式的正确运算顺序是什么?test(a++,++a,a++,++a,a++,++a)a=1;实际函数调用时,传入的参数值分别是多少?(
++*p++)–(--*q--)语义是什么?a=b=1,c=2,d=3;e=4;a的值是多少?HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之简单就是美这里没有答案,只有问题:我们问什么要写这样的代
码?工作太轻松?BUG不够多?水平显不出?…………如何改进?优先级搞不清楚用括号;复合语句太罗嗦,拆成几行来写;套用两句广告词:把简单的事情复杂化,太累把复杂的事情简单化,贡献!HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之简单就是
美编码的三不原则不要挑战自己的记性不要挑战同事的耐心不要挑战编译器的水平编码的三用原则能用简单语句的,就不要用复杂的技巧能用成熟代码的,就不要再来一套能用上工具的,就一定要机械化HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential我们要求什么?s
tructXXX{charcA;shortsB;longlC;};voidmain(){char*pChar;pChar=(char*)malloc(7);memcpy(pChar,"abcdefgh",sizeof(XXX));printf("%s\n",pChar);return
;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential我们要求什么?-续structXXX{charcA;shortsB;longlC;};voidmain(){char*pChar;pChar=(char*)malloc(7
);/*0,魔鬼数字;1,未申请成功怎么办?*/memcpy(pChar,“abcdefgh”,sizeof(XXX));/*2,内存越界*/printf(“%s\n”,pChar);/*3,没有字符串结束符*/return;/*4,没有释放内存*/}HUAWEITECH
NOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是
美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之sizeof数据结构是C语言的基础C语言的灵活性很大程度上在于其数据结构的灵活性要用好数据结构,首先要掌握数据结构大小的计
算系统为每个数据结构、每个变量都会分配一个对应的存储空间,这个存储空间的大小就是数据结构的尺寸HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之sizeoftypedefunionrecord{LONGlIn
dex;SHORTsLevel[6];CHARcPos;}REC_S;REC_SstMax,*pMax;CHARstr[]=“Hello”;CHAR*pChar=str;ULONGulGrade=10;USHORTusClass=10;DOUBL
EdWeightUCHAR*pCharArray[10][10];Sizeof(stMax/pMax/str/pChar/ulGrade/usClass/dWeight/pCharArray)的取值分别是多少?HUAWEITECHNOLOGIESCO.,LTD.HuaweiCon
fidential基础篇之sizeoftypedefunionrecord{LONGlIndex;SHORTsLevel[6];CHARcPos;}REC_S;REC_SstMax(12),*pMax(4);CHARstr[]=“Hello”(5+1=6,不
要忘了\0);CHAR*pChar=str(4);ULONGulGrade=10(4);USHORTusClass=10(2);DOUBLEdWeight(8);UCHAR*pCharArray[10][10](4×1
0×10=400);HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchca
se9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字节对齐随着半导体技术的发展,我们经历8bit、16bit、
32bit乃至64bit的CPU,我们产品当前大多使用32bitCPU从内存存取效率来说,4字节对齐的存取速度是最快的,非对齐情况下,CPU需要分解成两次32bit操作;缺省情况下,编译器自动对数据结构进行四字节对齐,以提高程序执行的效率,在特殊情况下,可以通过预编译指定指
定数据结构为1字节对齐或者其他;对于PowerPC/Intel系列CPU,在非四字节对齐情况下,由CPU自动完成两次操作,对上层应用透明;对于MIPSCPU,则需要通过编译选项进行干预,或者调整数据结果避免出现这种情况,否则会产生例外;字节对齐对数据结构的尺寸(sizeof)直接产生影响
HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字节对齐typedefstructHead{CHARsrc[6];ULONGulType;}HEAD_S;VOIDEncapsulat
ion(CHAR*pBuf){ULONGulLen,ulDestIP;CHAR*pData=pBuf;ulLen=sizeof(HEAD_S);pData+=ulLen;ulDestIP=VOS_NTOHL((IP_S*)pData->ulDe
stIP);return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字节对齐#pragmapack(push)#pragmapack(1)typedefstructHead{
CHARsrc[6];ULONGulType;}HEAD_S;#pragmapack(pop)VOIDEncapsulation(CHAR*pBuf){ULONGulLen,ulDestIP;CHAR*pData=pBuf;ulLen=
sizeof(HEAD_S);pData+=len;ulDestIP=VOS_NTOHL((IP_S*)pData->ulDestIP);(MIPSCPU异常)return;}HUAWEITECHNOLOGIESCO.,LTD.
HuaweiConfidential基础篇之字节对齐数据结构内部对齐,下面2种定义哪个好?typedefstructexample{USHORTusA;ULONGulA;USHORTusB;UCHARucA;USHOR
TusC;}EXAMPLE_SVStypedefstructexample{ULONGulA;USHORTusA;USHORTusB;USHORTusC;UCHARucA;UCHARucReserved;}EXA
MPLE_SHUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字节对齐案例点评在定义数据结构时(尤其是涉及协议和IPC通讯的时候),没有特殊理由的话,都定义成四字节对齐;这样做可能浪费几个字节,但是不会出问题;除了数据结构总长度是四字节对齐外,每
一个部分也要保证它是四字节对齐的(可以按照四字节、两字节、一字节的顺序排放数据结构中的各个域);对于无法定义成四字节对齐的数据结构,如以太网II、HDLC等,则将它们强行定义成一字节对齐,以规避这个问题;对于MIPSCPU,在必须面对非四字节对齐情况时,采用编译选项方式加以解
决;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.
简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字节序X86系统:VOIDQosConfigPolicy(){ulDestIP=从命令行读取用户配置的参数;pQosPolicy->ulDestIP=ulDestIP;retu
rn;}主机处理:VOIDQosClassify(){pIp=(IP_S*)pData;if(pIp->ulDestIp==pQosPolicy->ulDestIP){DoSomething();}retur
n;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字节序X86系统:VOIDQosConfigPolicy(){ulDestIP=从命令行读取用户配置的参数
;pQosPolicy->ulDestIP=ulDestIP;return;}主机处理:VOIDQosClassify(){pIp=(IP_S*)pData;if(VOS_HTONL(pQosPolicy->ulDestIP)==pIp->ulDestI
p){DoSomething();}return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字节序由于历史的原因,业界存在两种字节序标准:BigEndian和LittleEndian,PowerPC是大头,X86是小头,有些CPU
可以通过寄存器设置支持不同的字节序,例如MIPS;所谓大头就是高位在低字节,低位在高字节;小头则与此相反,以0x345678为例,大头内存从低到高的存放次序为00,34,56,78,小头内存从低到高的存放次序为78
,56,34,00;(上面的数值统一为16进制表示形式)字节序问题广泛存在于设备与设备之间、单板与单板之间、单板与底层芯片之间,只要两个处理单元的字节序不同,这个问题就存在,为了解决不同字节序的处理单元之间的通信问题,业界定
义了主机序和网络序的概念,网络序主要用于信息传递,一般不用于计算,其字节顺序与大头一致;除了在编码时绷紧这根弦以外,我们在器件选择时尽量选择主机序与网络序一致的芯片,同一设备的不同单板使用相同的字节序,并优先选择支持大头的芯片,这样,即使不能彻底解
决问题,也可以彻底规避问题。HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If
规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之函数参数在C语言中,函数通过返回值和参数与调用者交换信息,对参数理解和使
用的正确与否,直接影响到函数功能能否正确实现;函数参数自身占用的存储单元在堆栈中分配,入口参数指向的数值或者地址在函数入口处拷贝到堆栈区中,因此对函数参数所在存储单元的直接修改不会作用到函数之外,而对参数存储单元
中存放的地址指向的存储空间的修改,则会在函数之外其作用;调用者在进行函数调用之前,必须事先申明被调用函数的原型,包括返回值类型和参数类型;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之
函数参数BOOLGetMemory(CHAR*p){/*申请内存*/p=(CHAR*)malloc(100);if(NULL==p){returnFALSE;}else{returnTRUE;}}VOIDTest(void){CHAR*str=NULL;If(GetMemory(str
)){strcpy(str,"helloworld");printf(str);}return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之函数参数CHAR*
GetMemory(CHAR**p){/*申请内存*/*p=(CHAR*)malloc(100);return*p;}VOIDTest(void){CHAR*str=NULL;If(NULL!=GetMemory(&str)){strcpy(str,"helloworld")
;printf(str);free(str);str=NULL;}return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类
型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之返回值在C语言中,函数的调用者通过返回值了解
函数的执行情况;函数缺省的返回值类型为int,编程规范要求必须显示定义函数的返回类型;对于反映了函数执行状态的返回值,调用者必须依据返回值进行相应的处理,尤其是对于函数执行异常的情形;函数的出口参数能够起到与返回值类似的作用,上面一条规则对出口参数同样适用;对于函
数返回值为恒值的函数,建议使用VOID类型的返回值;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之返回值有什么问题?#include"stdlib.h“VOIDmain(){CHAR*p;p=(CHAR*)
malloc(100);VOS_Strcpy(p,“HelloWorld!\n”);printf(p);free(p);return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConf
idential基础篇之返回值#include"stdlib.h“VOIDmain(){CHAR*p;p=(CHAR*)malloc(100);if(NULL!=p){strcpy(p,“HelloWorld!\n”);printf(p);free(p);}retu
rn;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之返回值LONGA(){if(条件1){return;}returnVOS_OK;}VOIDB(){if(A())
{DoSomeThing1();}else{DoSomeThing2();}return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之返回值LONGA(){if(条件1){return
VOS_ERROR;}returnVOS_OK;}VOIDB(){if(A()){DoSomeThing1();}else{DoSomeThing2();}return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiCo
nfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfi
dential基础篇之强制类型转换强制类型转换给C语言编程带来了极大的灵活性,也正是这种灵活性,也埋下了无数的隐患;当目的结构的空间大于源结构的空间时,要重点关注内存访问超过源结构范围的情形,可能越界;当目的结构的空间小于源结构的空
间时,要重点关注对目的结构赋值不能完全覆盖源结构范围的情形,可能遗漏;与结构体之间的强制类型转换相比,基本数据结构的强制类型转换更容易出现上面描述的情况,使用的时候,一定要慎之又慎;HUAWEITECHNOLOGIESCO
.,LTD.HuaweiConfidential基础篇之类型转换——目的结构小于源结构VOIDB(CHAR*p){*p=1;return;}VOIDA(){ULONGa;B((CHAR*)(&a));return;}a=?,是1吗?H
UAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之类型转换——目的结构小于源结构VOIDB(CHAR*p){*p=1;return;}VOIDA(){ULONGa;B((CHAR*)(&
a));return;}a=?,是1吗?不可预知。HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之类型转换——目的结构大于源结构VOIDB(ULONG*p){*p=1000;return;}VOIDA(){UCHARa
=10;B((ULONG*)(&a));return;}在函数B给*p赋值之前,*p的值是多少?*p赋值之后,会出现什么样的情形?HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之类型转换——目的结构大于源结构VOIDB(UL
ONG*p){*p=1000;return;}VOIDA(){UCHARa=10;B((ULONG*)(&a));return;}在函数B给*p赋值之前,*p的值是多少?不可预知*p赋值之后,会出现什么样的情形?越界HUAWEITECHNOLOGIESCO.,LTD.Hu
aweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美
HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之switch…caseC语言使用switch…case处理一个条件的多个取值有不同的处理分支的情形;当所有的case都匹配不成功时,进入default分支,编程规范要求switch…case必须显示
设置default分支,如果程序从逻辑上不可能走到这个分支,可以在该分支中使用断言;结束case分支的执行最常用的办法是使用break/return,否则程序将自动进入下一个case分支继续执行;编译器对switch…case可以做优化,用空间换取时间;default分支按照编程规范
,要求放在switchcase的末尾,C语言本身不做强制要求;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之switch…caseVOIDmain(){LONGulCnt1=0,ulCnt2=0;CHAR*ch=“aha!”;while
(*ch){switch(*ch){case'a':case'h':ulCnt2++;default:ulCnt1++;}ch++;}printf("%u,%u\n",ulCnt1,ulCnt2);return;}ulCnt1和ulCnt2分别
是多少?HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之switch…caseVOIDmain(){LONGulCnt1=0,ulCnt2=0;CHAR*ch=“aha!”;while(*ch){switc
h(*ch){case'a':case'h':ulCnt2++;default:ulCnt1++;}ch++;}printf("%u,%u\n",ulCnt1,ulCnt2);return;}ulCnt1=4ul
Cnt2=3HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释
放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字符串ULONGBuildRun(CHAR**ppBuildrun){U
LONGulLen;CHAR*pBuf;ulLen=CalculateBuildRunLen();if(0==ulLen){*ppBuildrun=NULL;returnB_ZERO_LENGTH;}pBuf=VOS_malloc(0,ul
Len);if(NULL==pBuf){*ppBuildrun=NULL;returnB_MALLOC_FAILED;}VOS_StrCpy(pBuf,BuildRunInfo);*ppBuildrun=pBuf;returnVOS_OK;}HUAWEITECHNOLOGI
ESCO.,LTD.HuaweiConfidential基础篇之字符串ULONGBuildRun(CHAR**ppBuildrun){ULONGulLen;CHAR*pBuf;ulLen=CalculateBuildRunL
en();if(0==ulLen){*ppBuildrun=NULL;returnB_ZERO_LENGTH;}pBuf=VOS_malloc(0,ulLen+1);if(NULL==pBuf){*ppBuildrun=NULL;returnB_MALLOC_
FAILED;}VOS_StrCpy(pBuf,BuildRunInfo);*ppBuildrun=pBuf;returnVOS_OK;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字符
串案例点评:作为信息输出,字符串必不可少;字符串在动态申请时少分配一个字符是非常普遍的一个错误;strlen等计算字符串长度的函数都是不考虑字符串的\0结束符的;代码Review时,字符串越界问题是一个大客户,要盯紧看严;HUAWEITECHNOLOGIESCO.,LTD.HuaweiCo
nfidential基础篇之字符串(续)再看一个例子:LONGGetXYZHead(CHAR**pData,CHAR**pBuf){ULONGulLen;CHAR*pTmpData=*pData,*pTmpBuf=*pBuf;ulLen=Analysi
sHead(pTmpBuf);/*strcpy(pTmpData,pTmpBuf);*//*sprintf(pTmpData,“%s”,pTmpBuf);*//*memcpy(pTmpData,pTmpBuf,ulLen);*/returnulLen;}*pB
uf中存放是是XYZ协议的Peer发送过来的一段报文,这个函数负责将协议头拷贝到pData指向的空间中;假设空间是足够的,打算选择哪条语句;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字符串(续)LONGGetXYZHead(C
HAR**pData,CHAR**pBuf){ULONGulLen;CHAR*pTmpData=*pData,*pTmpBuf=*pBuf;ulLen=AnalysisHead(pTmpBuf);/*strcpy(pTmpData,pTm
pBuf);*//*sprintf(pTmpData,“%s”,pTmpBuf);*/memcpy(pTmpData,pTmpBuf,ulLen);returnulLen;}使用memcpy,因为没有人保证协议头中
不出现‟\0‟,而且协议头非常容易出现这个值,这个时候它就不再是字符串,字符串工具函数必须是专款专用,而memcpy则要宽泛得多;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之字符串(再续)VOIDGetDigi
tString(CHAR*pData,CHAR*pBuf){CHAR*pTmpData=pData,*pTmpBuf=pBuf;while(„\0‟!=(*pTmpBuf)){if((„0‟<=*pTmpBuf)&&(„9‟>=*pTmpBuf)){*pTmp
Data=*pTmpBuf;pTmpData++;}else{break;}pTmpBuf++;}return;}该函数的功能是将pBuf中的连续数字拷贝到pData中生成一个新的字符串HUAWEITECHNOLOGIESCO.,LTD.HuaweiC
onfidential基础篇之字符串(再续)VOIDGetDigitString(CHAR*pData,CHAR*pBuf){CHAR*pTmpData=pData,*pTmpBuf=pBuf;while(„\0‟!=(*pTmpBuf)){if((„0
‟<=*pTmpBuf)&&(„9‟>=*pTmpBuf)){*pTmpData=*pTmpBuf;pTmpData++;}else{break;}pTmpBuf++;}*pTmpData=„\0‟;/*没有尾字符
,就不是字符串*/return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换
8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之溢出#d
efineDEFAULT_EXPIRE_TIME300000/*5分钟*/VOIDARPRecordExpireTime(ARP_Entry_S*pArpEntry){/*计算表项预计老化时的时间,以系统启动以来的毫秒数表示*/pARPEntry->ulExpireTime=G
etBootTime()+DEFAULT_EXPIRE_TIME;return;}VOID*ARPExpire(ARP_Entry_S*pArpEntry){ARP_Entry_s*pArpNext;while(pArpEntry){if(GetBootTime()<pArpEnt
ry->ulExpireTime){break;}pArpNext=pArpEntry->pNext;Free(pArpEntry);pArpEntry=pArpNext;}return(VOID*)pArpEntry;}HUAWEITECHNOLOGI
ESCO.,LTD.HuaweiConfidential基础篇之溢出#defineDEFAULT_EXPIRE_TIME300000/*5分钟*/VOIDARPRecordExpireTime(ARP_Entry_
S*pArpEntry){/*计算表项预计老化时的时间,以系统启动以来的毫秒数表示*/pARPEntry->ulExpireTime=GetBootTime()+DEFAULT_EXPIRE_TIME;retu
rn;}VOID*ARPExpire(ARP_Entry_S*pArpEntry){ARP_Entry_s*pArpNext;while(pArpEntry){if(GetBootTime()<pArpEntry->ulExpireTime)/*
ULONG溢出如何处理?包括ExpireTime溢出、GetBootTime溢出*//*解决方案作为思考题*/{break;}pArpNext=pArpEntry->pNext;Free(pArpEntry);pArpEntry=pArpNext
;}return(VOID*)pArpEntry;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之溢出案例点评:在我们的系统中,溢出通常出现在时间处理上;系统时钟一般使用两个ULONG表示时间
,精确到毫秒;上层软件使用时间时一般忽略掉高位,只保留低32位。对于LONG的情况,25天后翻转;对于ULONG的情况,49天后翻转;如果没有特殊的需要,建议使用系统提供的精确到秒的32位时钟,在LONG情况下60年
翻转,基本可以不考虑这件事情;如果一定要使用毫秒钟,就需要考虑时钟翻转的情况;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之溢出(续)ULONGSequenceAdd(ULONGulCount){ULONGulSu
m=0;while(0<=ulCount){ulSum+=ulCount;ulCount--;}returnulSum;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之溢出(续)U
LONGSequenceAdd(ULONGulCount){ULONGulSum=0;while(0<=ulCount)/*条件永远为真,死循环*/{ulSum+=ulCount;ulCount--;}re
turnulSum;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之溢出(续二)VOIDShowLong(ULONGulCount){CHARstInfo[16];VOS_Spr
intf(stInfo,“%ld\n\r”,ulCount);Printf(stInfo);return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之溢出(续二)VOID
ShowLong(ULONGulCount){CHARstInfo[16];VOS_Sprintf(stInfo,“%lu\n\r”,ulCount);Printf(stInfo);return;}在显示无符号整数时,使用
正确的%描述符HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之溢出(续)案例点评:要解决溢出问题,首先要明确数据结构的取值范围;无符号数和有符号数在取值范围上的差异,也容易引起溢出;若非特殊需要,不要进行有符号数和无符号数的
强制类型转换,以免产生不必要的麻烦;若非特殊需要,不要进行从(U)LONG到(U)SHORT到(U)char的转换,以免产生不必要的麻烦;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6
.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之资源释放VOIDPrintDigit(ULONGulData){
CHAR*pBuf;pBuf=(CHAR*)malloc(16);if(NULL==pBuf){returnNULL;}VOS_Sprintf(pBuf,”%lu\n\r”,ulData);printf(pBuf);return;}HUAWEITECHNOLOGIESCO.,LTD.Hua
weiConfidential基础篇之资源释放VOIDPrintDigit(ULONGulData){CHAR*pBuf;pBuf=(CHAR*)malloc(16);if(NULL==pBuf){returnNULL
;}VOS_Sprintf(pBuf,”%lu\n\r”,ulData);printf(pBuf);Free(pBuf);/*Review九句箴言:看见Malloc找Free!*/return;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConf
idential基础篇之资源释放(续)Node_Head_S*CreateNode(ULONGulNType){Node_Head_S*pNode;Node_Body_S*pBody;pNode=(Node
_Head_S*)malloc(sizeof(Node_Head_S));if(NULL==pNode){returnNULL;}pBody=(Node_Body_S*)malloc(sizeof(Node_Body_S));if(NULL==pBody){returnNULL;}pNo
de->pBody=pBody;pNode->ulNType=ulNType;returnpNode;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之资源释放(续)Node_Head_S*CreateNode(ULONG
ulNType){Node_Head_S*pNode;Node_Body_S*pBody;pNode=(Node_Head_S*)malloc(sizeof(Node_Head_S));if(NULL==pNode){returnNULL;}pBody=(Node_
Body_S*)malloc(sizeof(Node_Body_S));if(NULL==pBody){Free(pNode);/*异常分支最容易忘记打扫战场,顾头也要顾尾*/returnNULL;}pNode->pBody=pBody;pNode->ulNT
ype=ulNType;returnpNode;}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之资源释放案例点评资源泄漏是代码Review中最常见的错误之一申请的每个资源必须明确由谁负责释放,何时释放,在何处释放;在异
常分支中,保持清醒的头脑,清理战场;在特定功能去使能时,需要完成的主要工作就是资源清退;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.size
of3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential
基础篇之if规范LONGIsZero(ULONGulCnt){if(ulCnt==0){returnW_ZERO;}else{returnW_NONZERO;}}函数的功能为:参数为0时返回W_ZERO;否则返回W_NOZERO;HUAWEITECHNOLOGIESCO.,
LTD.HuaweiConfidential基础篇之if规范LONGIsZero(ULONGulCnt){if(0==ulCnt){returnW_ZERO;}else{returnW_NONZERO;}}编程规范反复强调变量放在双等号的
右边,常量放在左边,就是为了规避出现If(ulCnt=0)这种语法正确,但是极有可能是笔误的情况。为了杜绝这种不必要的逻辑问题,要求必须严格遵守编程规范。HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfide
ntial基础篇之if规范(续)If(ulCnt=ulData){}VsulCnt=ulData;If(ulCnt){}VsIf(ulCnt==ulData){}上面的语句语法上都是正确的,但写法哪个好?HUAWEIT
ECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之if规范(续)If(ulCnt=ulData){}VsulCnt=ulData;If(ulCnt){}VsIf(ulCnt==ulData){}第一种和第三种非常容易出现笔误,为了杜绝不
必要的问题,不要使用第一种方式编写程序,而用方式二替代;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之if规范(再续)VOIDTest(){if(Func_A()&&Func
_B()){DoSomething_A();}else{DoSomething_B();}return;}在任何情况下是否语义都是正确的?HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之if规范(再续)VOIDTest(
)VOIDTest(){{ULONGulRet1,ulRet2;if(Func_A()){{ulRet1=Func_A();{ulRet2=Func_B();if(Func_B())if(ulRet1&&ulRet2)DoSomething_A();DoSomething_A();}}el
seelse{{DoSomething_B();DoSomething_B();}}}return;else}{DoSomething_B();}return;}如果程序逻辑为Func_A的返回值为假的情况下
,不执行Func_B,则上一页的程序是正确的,但是要求采用本页右侧的程序模式实现;如果Func_A和Func_B都无条件执行,再根据综合结果,决定走哪个分支,则使用本页左侧的程序;为了明确程序逻辑,同时要求使用注释加以说明,
以方便后期的维护HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之if规范(续三)VOS_Assert(Func_A())vsVOS_DBGASSERT(Func_A())这两个用法有什么区别?VOS_Aseert()用法保证在任何情况下
Func_A都得到执行;VOS_DBGASSERT则与系统是打开release宏还是debug宏相关:当系统打开了debug宏时,起语义与方式1完全相同;当系统打开的是release宏,则VOS_DBGASSERT在编译时将被忽略,Func_A自然页得不到运行;使用VOS_DBGASSERT
的时候要谨慎,要清楚了解不同系统宏下的不同语义,要保证两种场景下,程序逻辑都是正确的;为了避免不必要的麻烦,要求不允许在VOS_DBGASSERT中使用函数!HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfide
ntial基础篇之if规范(续四)LONGIsA(CHARch){if((„a‟!=ch)||(„A‟!=ch)){returnVOS_ERROR;}else{returnVOS_OK;}}函数功能为判断输入的字符是否是‟a
‟或者‟A‟,如果是,则返回VOS_OK,否则返回VOS_ERRORHUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之if规范(续四)LONGIsA(CHA
Rch){if((„a‟!=ch)||(„A‟!=ch))/*逻辑恒为真,逻辑错误,笔误?*/{returnVOS_ERROR;}else{returnVOS_OK;}}PC-LINT可以检查出逻辑恒为真或者假
的逻辑表达式,基本都是我们预期之外的逻辑,PC-LINT确实是一个好东西。HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential目录1.前言2.sizeof3.字节对齐4.字节序5.函数参数6.返回值7.强制类型转换
8.Switchcase9.字符串10.溢出11.资源释放12.If规范13.临界资源保护14.简单既是美HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之临界资源保护VOIDSend
MBuf(MBUF_S*pMBuf){空闲BD数=DRV_GetFreeBD();报文片数=MBUF_GetFrag(pMBuf);if(报文片数>空闲BD数){return;/*发送拥塞,暂时缓存*/}intr_lock();Co
pyMBufIntoBD();空闲BD数-=报文片数;intr_unlock();}TaskSOCK:Intr:{{…………SendMBuf(pMBuf);SendMBuf(pMBuf);…………}}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConf
idential基础篇之临界资源保护VOIDSendMBuf(MBUF_S*pMBuf){intr_lock();/*彻底保护*/空闲BD数=DRV_GetFreeBD();报文片数=MBUF_GetFrag(pMBuf);if(报文片数>空闲BD数){in
tr_unlock();/*打扫战场*/return(QOS_CONGEST);/*发送拥塞,暂时缓存*/}CopyMBufIntoBD();空闲BD数-=报文片数;intr_unlock();}TaskSOCK:Intr:{{…………SendMBuf(pMBuf);
SendMBuf(pMBuf);…………}}HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之临界资源保护案例点评这是一个经典的中断与任务之间临界资源缺乏保护的案例;中断与任务之间的临界资源保护通常采用在任务中关闭中断的方式进
行;关闭中断之后,对临界数据进行操作,操作完成之后再开放中断;这个案例说明对临界资源的读操作也是需要进行保护,如果读的结果是一个判断的输入条件的话;HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之临界资源保护(续)VOIDShow(S
LIST_S*pCfgSectionList){SLIST_S*pSectionList=pCfgSectionList,*pNext;while(pSectionList){pNext=pSectionList->pNext;EXEC_Outstring(0,pSectionList->pL
istName);/*有任务切换*/pSectionList=pNext;}return;}VOIDFreeSection(SLIST_S*pCfgSectionList){SLIST_S*pSectionList=pCf
gSectionList,*pNext;while(pSectionList){pNext=pSectionList->pNext;Free(pSectionList);pSectionList=pNext;}return;}HUAWEI
TECHNOLOGIESCO.,LTD.HuaweiConfidential基础篇之临界资源保护(续)VOIDShow(SLIST_S*pCfgSectionList){SLIST_S*pSectionList=pCfgSectionList,*pNext;L
ONGlHandle;while(pSectionList){pNext=pSectionList->pNext;lHandle=SetWaitlist(pNext);EXEC_Outstring(0,pSectionList->pListName);/*
有任务切换*/pSectionList=GetWaitlist(lHandle);}return;}VOIDFreeSection(SLIST_S*pCfgSectionList){SLIST_S*pSectionList=pCfgSectionList,*
pNext;while(pSectionList){pNext=pSectionList->pNext;DeleteWaitlist(pSectionList);Free(pSectionList);pSectionList=pNext;}return;}HUAWEITECH
NOLOGIESCO.,LTD.HuaweiConfidential基础篇之临界资源保护案例点评这是一个经典的任务之间临界资源缺乏保护的案例;在任务非抢占模型中,任务之间的临界资源保护问题一定出现在任务切换的时候;任
务切换之后,工作变量指向的内容可能发生变化,这个时候需要进行保护;解决任务之间临界资源报文的一个常用办法是使用WaitList,;产生任务切换的操作主要包括:同步IPC、RPC(包括同步、异步两种)、信号量同步读、队列同步读、事件同步读、Vos_T_Delay()以及其他包含了这些AP
I的函数调用;Thankyouwww.huawei.com