




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
最近开始学习Linux设备驱动程序第三版,参阅牛人关于嵌入式开发的准备知识点,编写了学习笔记。1、宏尽管在学习C的时候,牛人们往往不厌其烦的教导我们:应该尽量避免使用宏,但是在linux代码中宏的使用却非常普遍。除了移植性好,估计还是方便使然。使用宏最应该注意的是侧效可能引起的副作用,当然没有了类型检测,也是需要特别小心的地方。示例代码:/*写一个宏MAX ,输入两个参数并返回较大的一个*/#define MAX(a,b) (a) (b) ? (a) : (b)显然的,语义简单明了。这里用括号避免了侧效,但是得注意a、b类型。2、死循环关于的死循环的使用,牛人们提供了多种写法,一般有如下三种写法:A、while(1)B、for(;)C、LOOP:goto LOOP;有时候我也挺郁闷的,怎么会没有统一的写法呢?用哪种好呢?所以也尝试着分析了一下,以下是测试代码,并附上了VC6.0下的反汇编代码:int main(int argc, char *argv)int i=0, j=0;while(1)00401036 mov eax,10040103B test eax,eax0040103D je main+44h (00401054) if(i+ = 10)0040103F mov ecx,dword ptr ebp-400401042 mov edx,dword ptr ebp-400401045 add edx,100401048 mov dword ptr ebp-4,edx0040104B cmp ecx,0Ah0040104E jne main+42h (00401052) break;00401050 jmp main+44h (00401054) 00401052 jmp main+26h (00401036)for(;)if(j+ = 10)00401054 mov eax,dword ptr ebp-800401057 mov ecx,dword ptr ebp-80040105A add ecx,10040105D mov dword ptr ebp-8,ecx00401060 cmp eax,0Ah00401063 jne main+57h (00401067) break;00401065 jmp main+59h (00401069) 00401067 jmp main+44h (00401054)LOOP:if(k+ = 10)004013C0 mov edx,dword ptr ebp-0Ch004013C3 mov eax,dword ptr ebp-0Ch004013C6 add eax,1004013C9 mov dword ptr ebp-0Ch,eax004013CC cmp edx,0Ah004013CF jne LOOP+13h (004013d3) goto STEP_EXIT;004013D1 jmp STEP_EXIT+4 (004013d9) goto LOOP;004013D3 jmp LOOP (004013c0) STEP_EXIT:return 0;从VC6.0的汇编代码可以看出:B、C的效率是一样的,A多出了3条指令的判断代码,但是一般的情况下,牛人们又建议少使用goto,所以B是最优的选择。下面是GCC的汇编代码(编译环境Ubuntu9.10+GCC4.4.1):.file test.c.Text.globl main.type main, functionmain:pushl %ebpmovl %esp, %ebpsubl $16, %espmovl $0, -4(%ebp)jmp .L4.L10:nop.L4:cmpl $3, -4(%ebp)sete %aladdl $1, -4(%ebp)testb %al, %alje .L10nopjmp .L3.L11:nop.L3:cmpl $6, -4(%ebp)sete %aladdl $1, -4(%ebp)testb %al, %alje .L11nopjmp .L6.L12:nop.L6:cmpl $9, -4(%ebp)sete %aladdl $1, -4(%ebp)testb %al, %alje .L12nop.L8:movl $0, %eaxleaveret.size main, .-main.ident GCC: (Ubuntu 4.4.1-4ubuntu8) 4.4.1.section .note.GNU-stack,progbits可以看出GCC的汇编结果是A、B、C三种方法都一样。3、关于指针指针是C里面最重要的一个概念,其使用也是非常灵活,但是一些定义我总是一下子说不清楚,下面给出示例和解释:示例:用变量a给出下面的定义 指向整型数的指针 int *a; 指向指针的的指针,它指向的指针是指向一个整型数 nt *a; 有10个指针的数组,每个指针指向一个整型数 int *a10; 指向有10个整型数数组的指针 int (*a)10; 指向函数的指针,该函数有一个整型参数并返回一个整型数 int (*a)(int); 指针数组,每个指针都指向一个函数,该函数有个整型参数并返回整型数 int (*a10)(int); 关于指针,有一个重要的问题:就是野指针的防范。野指针的形成主要有如下可能:A、指针变量没有被初始化;B、指针被free或者delete之后,没有置为NULL;C、指针操作超越了变量的作用范围。解决之道如下:A、做好初始化;B、在内存回收后,立即设置指针为NULL;C、指针操作超越了变量的作用范围是比较难防范的,比如操作越界,临时变量被指针使用,都能造成野指针的出现,做好代码审查吧。4、关于关键字static在嵌入式开发中,关键字static经常被使用。下面就其三种使用方式及注意事项分别说明:A、局部static变量局部static变量有如下三个特点:(1) 存储空间分配在全局数据区,在程序整个运行期间都不释放。(2) 所处模块在初次运行时对其初始化,且只操作一次。(3) 如果不赋初值,编译器会自动赋初值0或空字符。注意事项是:static变量每次调用时,都指向同一块内存,具有“记忆性”,这样破环了所在模块的可重入性。这样在多线程程序设计或递归程序设计中,要特别注意这个问题。B、外部static变量/函数在C中static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。此时“static”的含义不是指存储方式,而是指变量/函数的作用域仅局限于本文件。这样做的好处就是:不用担心自己定义的外部变量/函数,是否会与其它文件中的同名。5、关于关键字const用const修饰的定义示例及解释如下:const int a; 一个常整型数 int const a; 一个常整型数 const int *a; 指向常整型数的指针(即整型数是不可修改的,但指针可以) int * const a; 指向整型数的常指针(被指向的整型数可以修改而指针不可修改) int const * a const; 指向常整型数的常指针(即指针及指向的整型数都是不可修改的) 得关注一个问题,就是为什么要使用关键字const呢?理由如下:A、声明一个参数为常量是为了告诉用户这个参数的应用目的;B、通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码;3) 使用关键字const可以利用编译器来保护那些不被改变的参数,防止其被无意的代码修改,这样可以减少bug的出现。6、关于关键字volatile一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:A、并行设备的硬件寄存器(如:状态寄存器);B、中断服务程序中会访问到的非自动变量(Non-automatic variables);C、多线程应用中被几个任务共享的变量。示例代码如下:int square(volatile const int *ptr)return *ptr * *ptr; 上面这段代码是问题代码,由于*ptr的值可能被意想不到地改变,因此return的值可能是两个不同数的积。正确的代码如下:long square(volatile const int *ptr)int a;a = *ptr;return a * a; 6、关于位操作位操作在嵌入式开发中也是经常被用到的。位域(bit fields)可移植性差,建议避免使用,而使用宏和位掩码(bit masks)操作。示例代码如下:#define BIT3 (0x1 6) ? puts( 6) : puts(6。理由原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。9、单位字长问题示例代码如下:unsigned int compzero = 0xFFFF; 对于一个int型不是16位的处理器为说,上面的代码是不正确的。而应编写如下:unsigned int compzero = 0;这一问题真正能揭露出处理器字长的重要性,也能够说明移植性好的代码的好处。10、关于内存泄漏的防范和检测方法A、采用代码审查的方式进行控制这种方法是最容易想到的,但是效果也是相当的有限的。当程序复杂度增加的时候,这种方法就越加显得无能为力了。B、采用一定的工具来帮助发现内存泄漏使用工具用于检测内存泄漏时,应当注意两点:第一、要保证代码在测试时有尽可能高的代码覆盖率。这是因为,内存泄漏的检测需要代码被执行到了,检测工具才能发现。现实情况是,往往很难做到百分之百的代码覆盖率,因此检测的效果也是有限的。第二、工具对被测程序(代码)的性能可能有较大的影响,如果内存泄漏检测工具使用时造成程序无法正常运行,那么这类工具也是无法使用的。C、采用一定的封装技术对内存的分配与释放进行接管通常提供一个模块或是库对malloc()、free()、new、delete进行很薄的一层封装,然后向应用程序提供相应的API用于分配和释放内存。此外,这个封装层还提供一定的方式让我们能实时的得到运行时内存的使用情况,就可以随时知道内存的使用情况。对于上面三种情况,从解决方案来看第三种方案最好,但其也存在一些值得关注的问题:其一,由于内存管理模块对于每一次内存分配需要记录在哪个文件以及文件的哪一行以用于在需要时显示这些信息。因此,存在一定的内存开销。其二,由于增加了一层的封装,尽管很薄,但内存的分配速度还是会有一点点下降,下降的程序取决于管理算法。从以上两点来看,第三种方法是通过时间和空间来换取实用性的。前面两种方法,在使用上过度的依赖于人或工具,所以很不方便,且对于运行时内存泄漏检测存在一定的局限性。第三种方法的可操作性还存在一个问题,比如,程序员并没有采用封装后的API,而是仍然不小心调用了C/C+库的malloc()和new,那么对于这些内存分配操作,其绕过了内存管理模块。对于这一问题,解决方法就是通过代码审查或是采用搜索工具(很多代码编辑工具都提供搜索功能)进行搜索,看看malloc()和new是否被调用了,以防止这类事情的发生。11、关于typedef关于typedef在linux中使用也是比较多的,其最大的优点就是使代码移植性好。示例代码如下:typedef INT int;我们使用一个有符号的整形时,可以使用INT来定义,在跨平台使用时,只需要修改“typedef INT int;”而并不需要修改诸多使用INT的代码。示例代码如下:#define dPS struct s *typedef struct s * tPS;dPS p1,p2; /*代码A*/tPS p3,p4; /*代码B*/代码A中“dPS p1,p2;”扩展为“struct s * p1, p2;”,即p1为一个指向结构的指针,p2为一个实际的结构对象。代码B正确地定义了p3和p4两个指针。12、关于字符串字符串其实就是一个数组(指针),字符串末尾的0。程序中字符串是比较常用的,在使用过程中,我们最容易犯的错误就是忘记了结束符。示例代码如下:char str = 1234567;int len1,len2;len1=strlen(str);len2=sizeof(str);这里len2 = len1+1,原因就在于len1仅仅是字符串的字符总数,len2是数组的长度。13、字节对齐/*以16字节(注意是字节byte不是位bit)对齐的方式分配一个变量*/int x _attribute_ (aligned (16) = 0;/*对结构体成员变量设置该属性,例如,创建一个双字对齐的int对*/struct _examint x2 _attribute_ (aligned (8); 可以手动指定对齐的格式,也可以使用默认的对齐方式。如果aligned后面不紧跟一个指定的数字值,那么编译器将依据你的目标机器情况使用最大最有益的对齐方式。例如:short array3 _attribute_ (aligned);选择针对目标机器最大的对齐方式,可以提高拷贝操作的效率。aligned属性使被设置的对象占用更多的空间,相反的,使用packed可以减小对象占用的空间。需要注意的是,attribute属性的效力与你的连接器也有关,如果你的连接器最大只支持16字节对齐,那么你此时定义32字节对齐也是无济于事的。struct test long long ll;int x2 _attribute_ (packed);使用packed属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐。 14、函数函数重入是比较容易被忽视的一个问题。那什么是可重入函数呢?若一个函数可以安全的被并行执行,则称其为可重入(reentrant或re-entrant)的。即当该函数正在运行时,可以再次进入并执行它。若一个函数是可重入的,则必须满足以下规则:A、不能含有静态(全局)非常量数据。B、不能
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 外用消毒药品应用指南
- 唾液腺肿瘤手术护理查房
- 宁夏吴忠市青铜峡高中2026届高三上化学期中联考试题含解析
- 舞蹈舞台汇报课
- 社区教育成果汇报
- 天然药物资源开发与利用
- 社交圆场技术介绍
- 全屋定制整体讲解
- 形式科学与技术
- 香奈儿企业讲解
- 2024年7月浙江省高中学业水平考试数学试卷真题(含答案详解)
- DL∕T 782-2001 110kV及以上送变电工程启动及竣工验收规程
- 《公路桥梁施工监控技术规程》(JTGT3650-01-2022)
- DL∕T 5161.1-2018 电气装置安装工程质量检验及评定规程 第1部分:通则
- 思想政治教育原理方法论
- 机器人技术在制造业应用
- 2024年春季学期 形势与政策 第六讲 当前就业形势与实施就业优先战略
- JJG 692-2010无创自动测量血压计
- 医务人员职业暴露报告卡
- 四年级上册语文文学常识
- 工匠现场答辩方案
评论
0/150
提交评论