




已阅读5页,还剩1页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C语言嵌入式系统编程修炼之内存操作 - - - -数据指针1w,U748m,e/D/S8v5Z3%,j$L电子开发论坛在嵌入式系统的编程中,常常要求在特定的内存单元读写内容,汇编有对应的MOV指令,而除C/C+以外的其它编程语言基本没有直接访问绝对地址的能力。在嵌入式系统的实际调试中,多借助C语言指针所具有的对绝对地址单元内容的读写能力。以指针直接操作内存多发生在如下几种情况:.v!k/D2R,D&P9P1e电子开发论坛5P#*G6o(?#d(1) 某I/O芯片被定位在CPU的存储空间而非I/O空间,而且寄存器对应于某特定地址;电子论坛,电子设计论坛,电子开发论坛24P8E-A 6Z;A/j*H d9m6K电子论坛,电子设计论坛,电子开发论坛(2) 两个CPU之间以双端口RAM通信,CPU需要在双端口RAM的特定单元(称为mail box)书写内容以在对方CPU产生中断;+N z1b5t7b8M8y电子开发论坛n4?8o5J-x7Z(3) 读取在ROM或FLASH的特定单元所烧录的汉字和英文字模。!p8j24r9e电子开发论坛#-)J2P592譬如: $e4X4m2U,X.? o:Vp:I(f!n.N/P1D9D7Aunsigned char *p = (unsigned char *)0xF000FF00;电子论坛,电子设计论坛,电子开发论坛$B+G$z$m:U(Q-y;p$u*p=11; 全球最大的中文电子开发论坛3e-j00c1O:X+_&F J3?_3bq1z以上程序的意义为在绝对地址0xF0000+0xFF00(80186使用16位段地址和16位偏移地址)写入11。E2d C6f&L/E9S7L电子论坛,电子设计论坛,电子开发论坛3Z.i-C*s1D在使用绝对地址指针时,要注意指针自增自减操作的结果取决于指针指向的数据类别。上例中p+后的结果是p= 0xF000FF01,若p指向int,即:4N(L3p l-r0Y&y$L-O#/Q2r,W$s9$int *p = (int *)0xF000FF00; 电子论坛,电子设计论坛,电子开发论坛$H9 w7o&6o(?电子开发论坛2J*H,J.&e9k-G*?6_p+(或+p)的结果等同于:p = p+sizeof(int),而p-(或-p)的结果是p = p-sizeof(int)。电子开发论坛/M6Xl4U5b)v3t5U1S3X:?;t,4同理,若执行:2|8kk0;1n,D4Y/O k-m 全球最大的中文电子开发论坛)m%R9o:D3U8m0/w.x;P电子论坛,电子设计论坛,电子开发论坛long int *p = (long int *)0xF000FF00; 全球最大的中文电子开发论坛/U p4gd:G&M _;p%G z2n(a$r3P9q%则p+(或+p)的结果等同于:p = p+sizeof(long int) ,而p-(或-p)的结果是p = p-sizeof(long int)。电子论坛,电子设计论坛,电子开发论坛(Z.a5E#D R,j$c#w:R8:c(t$|(M!1B9r45_记住:CPU以字节为单位编址,而C语言指针以指向的数据类型长度作自增和自减。理解这一点对于以指针直接操作内存是相当重要的。电子论坛,电子设计论坛,电子开发论坛7X&Q&H;D+J77V Uy2w&P函数指针2j%b/ s+o(yf电子论坛,电子设计论坛,电子开发论坛8G,o8y6E*h)A电子开发论坛首先要理解以下三个问题:S!O;q2|3L&S-22d电子论坛,电子设计论坛,电子开发论坛7d+F-u+?2u -U02(1)C语言中函数名直接对应于函数生成的指令代码在内存中的地址,因此函数名可以直接赋给指向函数的指针;6W5G0L8Bq:Oj9a.A5z&O6a:T!j00P+g电子开发论坛(2)调用函数实际上等同于调转指令参数传递处理回归位置入栈,本质上最核心的操作是将函数生成的目标代码的首地址赋给CPU的PC寄存器;C72)b7o.l&i4S+i电子论坛,电子设计论坛,电子开发论坛1q7dR6t2U7l电子开发论坛(3)因为函数调用的本质是跳转到某一个地址单元的code去执行,所以可以调用一个根本就不存在的函数实体,晕?请往下看: 电子开发论坛.eH7:m*i+I5q?(N 全球最大的中文电子开发论坛D*X:u!n0O3n&q$V5F请拿出你可以获得的任何一本大学微型计算机原理教材,书中讲到,186 CPU启动后跳转至绝对地址0xFFFF0(对应C语言指针是0xF000FFF0,0xF000为段地址,0xFFF0为段内偏移)执行,请看下面的代码:#X*g8h;_2D m/#r T&T(T电子开发论坛*G:t0j,U&D5dtypedef void (*lpFunction) ( ); /* 定义一个无参数、无返回类型的 */k(Y$u(i,aV/f2q 全球最大的中文电子开发论坛/* 函数指针类型 */;e 2w0X8f1UK+%E电子论坛,电子设计论坛,电子开发论坛lpFunction lpReset = (lpFunction)0xF000FFF0; /* 定义一个函数指针,指向*/;nO9U/z)w%j;B电子论坛,电子设计论坛,电子开发论坛/* CPU启动后所执行第一条指令的位置 */)X%J$H+)B&F#c*Q电子论坛,电子设计论坛,电子开发论坛lpReset(); /* 调用函数 */ (C0u0y%b&G3*o:X/c电子开发论坛8l-P !U#_,t0a$G%U6N3u0k2d电子论坛,电子设计论坛,电子开发论坛在以上的程序中,我们根本没有看到任何一个函数实体,但是我们却执行了这样的函数调用:lpReset(),它实际上起到了软重启的作用,跳转到CPU启动后第一条要执行的指令的位置。(S7C:l(b+z%8|2s1O(g,s$qQ#d(M9N电子论坛,电子设计论坛,电子开发论坛记住:函数无它,唯指令集合耳;你可以调用一个没有函数体的函数,本质上只是换一个地址开始执行指令!电子论坛,电子设计论坛,电子开发论坛-o+?7W27pEI%q3Z1Y z!O#Y9Z*s:s5F3U6t!X电子论坛,电子设计论坛,电子开发论坛数组vs.动态申请/t/U)6W-J3b:k电子论坛,电子设计论坛,电子开发论坛,J7o#M9h2v*k在嵌入式系统中动态内存申请存在比一般系统编程时更严格的要求,这是因为嵌入式系统的内存空间往往是十分有限的,不经意的内存泄露会很快导致系统的崩溃。6UZ7c)!W$电子论坛,电子设计论坛,电子开发论坛(%P6X.m#i!W&N,X;N所以一定要保证你的malloc和free成对出现,如果你写出这样的一段程序:(./R!.v.U*$O电子论坛,电子设计论坛,电子开发论坛3P2gg2g Q06w:jchar * function(void)k9p;m9v:(M/C电子论坛,电子设计论坛,电子开发论坛电子论坛,电子设计论坛,电子开发论坛*t*w2?6i*m6b1J0k*qchar *p;*K:?6Q*F+D._ 5?0Y电子开发论坛p = (char *)malloc();电子论坛,电子设计论坛,电子开发论坛!H%K#.7p:B%|;5Fif(p=NULL)5h/C-z0O6y3n2B#z5;,T3z+R)iV(s-y/. 全球最大的中文电子开发论坛 /* 一系列针对p的操作 */电子论坛,电子设计论坛,电子开发论坛4b!e-N a$L+k2j!u2ireturn p; 电子开发论坛o6q!K F;n1|5T)x)N ;f a+y8c6L+S%eN#L3U8f 在某处调用function(),用完function中动态申请的内存后将其free,如下:电子开发论坛7h g;g;J*)E7f4r+R:d/i0a3X(W+W 全球最大的中文电子开发论坛char *q = function(); 全球最大的中文电子开发论坛;w9)P0p82s/电子论坛,电子设计论坛,电子开发论坛 z$t2f8N.|*l91mn5Cfree(q); )S-t95?.U2B$l/L)k电子论坛,电子设计论坛,电子开发论坛9X&m%M+u+D上述代码明显是不合理的,因为违反了malloc和free成对出现的原则,即谁申请,就由谁释放原则。不满足这个原则,会导致代码的耦合度增大,因为用户在调用function函数时需要知道其内部细节! 全球最大的中文电子开发论坛 |(I;&|-i-J%?(n5p&?5y $f.f#a_*f0t/_ 全球最大的中文电子开发论坛正确的做法是在调用处申请内存,并传入function函数,如下:/a0w7c%aa&-(l%a%z7.g8T1Y(y8_*Dchar *p=malloc();0!w5T,)t7e)电子论坛,电子设计论坛,电子开发论坛if(p=NULL)电子论坛,电子设计论坛,电子开发论坛)y&q,u9_2c y V(c%T;B2A/h y9d4#E 全球最大的中文电子开发论坛function(p);电子开发论坛 x9T(j82H b Q/?*x#S.efree(p);2i1Vz!8C%|)U:H,R 全球最大的中文电子开发论坛p=NULL; #m%w,J$&;N!L.Z7u7.s3C,K电子论坛,电子设计论坛,电子开发论坛而函数function则接收参数p,如下:1O26f+e8?!X0n电子论坛,电子设计论坛,电子开发论坛!b3-V5y,x h,R5g g电子开发论坛void function(char *p)+k&A8E)_;j$Zs*D电子开发论坛电子论坛,电子设计论坛,电子开发论坛0&u2f5W F2N u1I4Q /* 一系列针对p的操作 */$?(W-b%9M5R*i*z电子论坛,电子设计论坛,电子开发论坛 8y$J,H?9%I%H+|2C$P$W 全球最大的中文电子开发论坛基本上,动态申请内存方式可以用较大的数组替换。对于编程新手,笔者推荐你尽量采用数组!嵌入式系统可以以博大的胸襟接收瑕疵,而无法海纳错误。毕竟,以最笨的方式苦练神功的郭靖胜过机智聪明却范政治错误走反革命道路的杨康。!pE)u1R$R0IL(F$y3k9_1FP3u&j 全球最大的中文电子开发论坛给出原则: 全球最大的中文电子开发论坛6$M2A5M#N$u,K;C%J)1A2|1Z3F&c2Q4U;J*?(1)尽可能的选用数组,数组不能越界访问(真理越过一步就是谬误,数组越过界限就光荣地成全了一个混乱的嵌入式系统);%|*j)E5v;A01b&w.|!A0G电子论坛,电子设计论坛,电子开发论坛电子论坛,电子设计论坛,电子开发论坛8d OI5Y1U!O3(Z9P(2)如果使用动态申请,则申请后一定要判断是否申请成功了,并且malloc和free应成对出现!4l-A$k!D l(X#w,v7x电子论坛,电子设计论坛,电子开发论坛1S3k)Ul.n%z关键字const+z)m&M2$_0B电子论坛,电子设计论坛,电子开发论坛-F6W(p:J0H+S6b.b?9Wconst意味着只读。区别如下代码的功能非常重要,也是老生长叹,如果你还不知道它们的区别,而且已经在程序界摸爬滚打多年,那只能说这是一个悲哀:-K:T9P9x5W&Y8;P电子论坛,电子设计论坛,电子开发论坛电子论坛,电子设计论坛,电子开发论坛7i+G&h#r,p!/Aconst int a;电子开发论坛3K#o7?/F8j0A0nint const a;!J_#V+g8m*AT5x-a%E电子论坛,电子设计论坛,电子开发论坛const int *a; 全球最大的中文电子开发论坛+DJV#B#h#Q8)j%3ydint * const a; 全球最大的中文电子开发论坛0d+i8Z(,3wint const * a const; /v9 x7r*f$G1X+zg#v/h电子开发论坛(1) 关键字const的作用是为给读你代码的人传达非常有用的信息。例如,在函数的形参前添加const关键字意味着这个参数在函数体内不会被修改,属于输入参数。在有多个形参的时候,函数的调用者可以凭借参数前是否有const关键字,清晰的辨别哪些是输入参数,哪些是可能的输出参数。3z I#?$s-Z电子开发论坛8Y*5B5d#m(2)合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改,这样可以减少bug的出现。电子开发论坛!+0x.C6K7V3L4I)3|!8p#v&0|*e-Xconst在C+语言中则包含了更丰富的含义,而在C语言中仅意味着:只能读的普通变量,可以称其为不能改变的变量(这个说法似乎很拗口,但却最准确的表达了C语言中const的本质),在编译阶段需要的常数仍然只能以#define宏定义!故在C语言中如下程序是非法的:6l%G2P:R%w7T(x.x电子开发论坛*.q7uL3| ?7zconst int SIZE = 10;&j1P*5eg6!we电子开发论坛char aSIZE; /* 非法:编译阶段不能用到变量 */ +R(M2C/b6_-K4B7电子论坛,电子设计论坛,电子开发论坛b3E%N s7W电子论坛,电子设计论坛,电子开发论坛关键字volatile5D!E/K0s0-k%3z 全球最大的中文电子开发论坛 全球最大的中文电子开发论坛+Y+x%O 4O8Q2e1JC语言编译器会对用户书写的代码进行优化,譬如如下代码:电子开发论坛&7N&+R&e489g7Y,DR5y9电子开发论坛int a,b,c;&,Q(n&?&g0R;T电子论坛,电子设计论坛,电子开发论坛a = inWord(0x100); /*读取I/O空间0x100端口的内容存入a变量*/X;d e:Z/L电子开发论坛b = a;8-,W xa = inWord (0x100); /*再次读取I/O空间0x100端口的内容存入a变量*/ 全球最大的中文电子开发论坛1.Q:l2Y2u-U%d/R4wc = a; 全球最大的中文电子开发论坛,N !f$a+j%p1K#u9P-y7l6j$j&b67R+很可能被编译器优化为:7x08w.X)Y35Oi9F37NI%e%D+C电子论坛,电子设计论坛,电子开发论坛int a,b,c;电子开发论坛3n z:z!f9R(ya = inWord(0x100); /*读取I/O空间0x100端口的内容存入a变量*/电子论坛,电子设计论坛,电子开发论坛-b9P 1P-T*|&s2Fb = a;电子论坛,电子设计论坛,电子开发论坛1i:(2K1y+W$v9hc = a; (T%4j:y/e!t(O5u3y(i!W-P*w.A(j;i(Xh!O但是这样的优化结果可能导致错误,如果I/O空间0x100端口的内容在执行第一次读操作后被其它程序写入新值,则其实第2次读操作读出的内容与第一次不同,b和c的值应该不同。在变量a的定义前加上volatile关键字可以防止编译器的类似优化,正确的做法是:电子论坛,电子设计论坛,电子开发论坛#3u.zU7b6n6*s9J!7i/b-B电子开发论坛volatile int a; Y1Z8U9r8_8p 全球最大的中文电子开发论坛z-xm*a&D/l0S&Q 全球最大的中文电子开发论坛volatile变量可能用于如下几种情况:#M%m/e:z6M$y+M&-o-I8n4b (U(n$i-qq/%y6?$d6j$N(1) 并行设备的硬件寄存器(如:状态寄存器,例中的代码属于此类);*|&r,U86b4J:Q电子论坛,电子设计论坛,电子开发论坛 全球最大的中文电子开发论坛8I8uZ2g2q#o(G-Z&p*W#y(2) 一个中断服务子程序中会访问到的非自动变量(也就是全局变量);;|6x6-l8N0.K.n!F%#C3Y&W$(3) 多线程应用中被几个任务共享的变量。1H a$h)*f)x3t0z;I 全球最大的中文电子开发论坛电子论坛,电子设计论坛,电子开发论坛)aZ+:B7B:S6S+o:CPU字长与存储器位宽不一致处理电子论坛,电子设计论坛,电子开发论坛4E*a20Y(B#qE:v!T7n&M-9u;m)_&/Y1e.?电子论坛,电子设计论坛,电子开发论坛在背景篇中提到,本文特意选择了一个与CPU字长不一致的存储芯片,就是为了进行本节的讨论,解决CPU字长与存储器位宽不一致的情况。80186的字长为16,而NVRAM的位宽为8,在这种情况下,我们需要为NVRAM提供读写字节、字的接口,如下: ;i#T/0F7F:H1o.I$z,y&G%r j电子论坛,电子设计论坛,电子开发论坛typedef unsigned char BYTE;电子论坛,电子设计论坛,电子开发论坛|*_+U0y6q6i6typedef unsigned int WORD; 电子论坛,电子设计论坛,电子开发论坛0r3x23)X2I/* 函数功能:读NVRAM中字节 a$V6q2M.P9A* 参数:wOffset,读取位置相对NVRAM基地址的偏移-_:T2N1+Y#B#T* 返回:读取到的字节值 全球最大的中文电子开发论坛8g*J:Eu8*/:Do$B0!Z,K&p 全球最大的中文电子开发论坛extern BYTE ReadByteNVRAM(WORD wOffset)*R!D;q,M)T;O+S电子论坛,电子设计论坛,电子开发论坛电子论坛,电子设计论坛,电子开发论坛9x7M*d91Y z9QH!y6GLPBYTE lpAddr = (BYTE*)(NVRAM + wOffset * 2); /* 为什么偏移要2? */!o2d!j|5p5e)i6D电子论坛,电子设计论坛,电子开发论坛;B4_!l3M2o5V+G A(L61return *lpAddr;2B)t/K:Y:G#3M)z$#70oF):T4e)Z%i+tT2m1U9gf;g.G/* 函数功能:读NVRAM中字电子开发论坛)y(X.S(_-ja+v)Q$I* 参数:wOffset,读取位置相对NVRAM基地址的偏移电子开发论坛&a9ON/*C* 返回:读取到的字 全球最大的中文电子开发论坛;A)a7C0D7:u*/电子开发论坛3.a9A%_8p!E5P)extern WORD ReadWordNVRAM(WORD wOffset)-3_%M;f#s)1z#L1k X 全球最大的中文电子开发论坛电子开发论坛+i5q1/Z:s!y6F!e9dWORD wTmp = 0;-x/9E;J*b7?电子开发论坛LPBYTE lpAddr;!T!;J2X1Z 全球最大的中文电子开发论坛/* 读取高位字节 */电子开发论坛!dA-5I9m,q0H0WlpAddr = (BYTE*)(NVRAM + wOffset * 2); /* 为什么偏移要2? */ #w)z2E B:;电子论坛,电子设计论坛,电子开发论坛wTmp += (*lpAddr)*256;5d*x1G/c/y6a4Z电子论坛,电子设计论坛,电子开发论坛/* 读取低位字节 */4|6W8e6R7e9n4A电子论坛,电子设计论坛,电子开发论坛lpAddr = (BYTE*)(NVRAM + (wOffset +1) * 2); /* 为什么偏移要2? */ 全球最大的中文电子开发论坛+6g4K5M,a*O-MwTmp += *lpAddr;:U)?:A).F/J7c_return wTmp;?0b$B8|5U:j&g9m9k7Tq*h8d/c:F/a 全球最大的中文电子开发论坛-u!x8SO,Q)L5S/* 函数功能:向NVRAM中写一个字节 6c;_%Q6m5Tf&W%s.W/e*参数:wOffset,写入位置相对NVRAM基地址的偏移+J9P G#N:K6F.* byData,欲写入的字节2%L9?4B4c7L3V*/;P9m&sQ#J1G%.Y2x:S%extern void WriteByteNVRAM(WORD wOffset, BYTE byData)1g.e6e3i!)S(T)y电子开发论坛电子开发论坛$T7i5D0o(g! 全球最大的中文电子开发论坛%O8e&L.p+S+|,B*I:,A)w1a,j3x1.i)3W*o电子论坛,电子设计论坛,电子开发论坛/* 函数功能:向NVRAM中写一个字 */2O/VQ8z6c.k0h0_)S)m&*参数:wOffset,写入位置相对NVRAM基地址的偏移8u#N,D I电子开发论坛* wData,欲写入的字电子论坛,电子设计论坛,电子开发论坛*b2*j8Ak0C Am
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 顾客咨询方案范文大全
- 建筑模板工程安装方案设计
- 办公建筑渲染方案设计
- 咨询室开业营销方案
- 高层门窗淋水施工方案
- 外贸营销咨询方案模板
- 有轨巷道堆垛机施工方案
- 飘窗改造方案咨询
- 咨询年度方案模板
- 少儿阅读打卡活动方案策划
- 小学生防霸凌课件教学
- 2025年农业灌溉水肥一体化技术应用现状与发展报告
- 高温合金蠕变行为研究-洞察阐释
- 2025年卫生系统招聘考试医学基础知识新版真题卷(附详细解析)
- 瓦斯异常预警管理制度
- 2025春季学期国开电大本科《人文英语4》一平台机考真题及答案(第七套)
- 贵州贵州贵安发展集团有限公司招聘考试真题2024
- 跨境人民币合同协议
- 三方散伙协议合同协议
- 邮政社招笔试试题及答案
- 产程中饮食管理
评论
0/150
提交评论