printf在uCOS上的移植和浮点数显示.docVIP

  • 11
  • 0
  • 约1.37万字
  • 约 12页
  • 2017-09-17 发布于江苏
  • 举报
printf在uCOS51上的移植和浮点数显示 asdjf@163.com 2003/10/20 printf函数是C语言里应用最为广泛的函数之一,我们初学C语言时实现的第一个程序《Hello the world》,就包含printf语句。它的应用十分灵活,可以打印各种类型数据,可变数量的变量,表达式,是非常理想的输出函数,广泛用于结果输出,中间变量显示,调试等。然而,编译器将其作为标准库函数,不提供源代码,其本身代码量也偏大,无法实现嵌入式系统按需裁减的要求,并且有些printf库代码不支持重入。 解决方法是把Linux里的相关源码简化后移植到C51里。关键点在于理解变参函数、参数传递规则、浮点数存储格式。 C编译器一般将函数参数按从右至左的顺序依次压入堆栈(C51在使用reentrant关键字后也这么处理),函数内部处理参数变量时直接在堆栈上寻址,局部变量紧跟在参数后面存放,函数返回时出栈,参数和局部变量所占用空间自动释放。例如: fun(char *fmt,char a,int b long c,float d) reentrant 的堆栈结构如图1所示: ------------------ |float d 4 bytes | +10 ------------------ |long c 4 bytes | +6 ------------------ |int b 2 bytes | +4 ------------------ |char a 1 bytes | +3 ------------------ |char *fmt 3bytes| SP+0-------------------- | 局部变量 | ------------------ 图1.fun函数参数和局部变量在堆栈里的结构 C51编译器从右向左依次将float/long/int/char/char *压入仿真堆栈,各种数据类型所占空间大小如图1,例如char占1字节,float占4字节等。值得一提的是,常数压栈的格式:0-255按1字节压栈,256-32767压成2字节,32768(8000H)或以上压成4字节,带有l/L结尾的常数占4字节。 上面的函数fun内部可以通过函数名称访问各个变量,C编译器自动把函数名转换成地址,如:访问long c转换成访问SP+6,访问char a转换成访问SP+3等。写成表达式为: c=0======(SP+6)=0 a=y;=============(SP+3)=y 总之,上面的函数通过显式地指定函数名和数据类型完成参数的传递和访问,内部细节由C编译器完成,对用户透明。 这种方式的好处是表达清晰,结构严谨,屏蔽底层细节;坏处是不够灵活,参数必须在处理前显式确定并固定不变,这给我们用同一函数处理不同情况带来了困难,C的解决方案是引入“变参函数”(详见C语言大全),如下: fun(char *fmt,...) reentrant ...表示有0到N个可变数量参数,C编译器此时不检查参数匹配,传递参数规律与一般函数相同。如果我们用这个函数取代前一个函数,但仍按前一函数的调用方式调用,那么,参数在堆栈里的位置仍如图1所示。此时,函数形参只有“...”没有具体变量名,如何引用形参变量呢?观察图1堆栈结构可知,如果知道堆栈内第一个参数的起址和每个参数的数据类型及他们的排列顺序,就可以通过指针访问指定的变量。例如: 知道堆栈内第一个参数的起址SP和每个参数的数据类型及排列顺序(char*/char/int/long/float),就可以通过SP,SP+3,SP+4,SP+6,SP+10访问原来必须通过参数名访问的fmt,a,b,c,d变量。写成C语言就是: fun(yy,y,(int)2,5L,-12.5); fun(char *fmt,...) reentrant { void *p; p=fmt; //此时*p指向字符串yy首址,**p是字符串第一个

文档评论(0)

1亿VIP精品文档

相关文档