官方QQ群收藏本站

百问linux嵌入式论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2881|回复: 2

【分享】裸机移植printf功能

[复制链接]

14

主题

68

帖子

211

积分

版主

Rank: 7Rank: 7Rank: 7

积分
211
发表于 2012-4-17 10:35:00 | 显示全部楼层 |阅读模式
裸机移植printf功能


.可变参数函数的原型声明
typeVAFunction(type arg1, type arg2, … );
参数可以分为两部分:个数确定的固定参数和个数可变的可选参数。函数至少需
要一个固定参数,固定参数的声明和普通函数一样;可选参数由于个数不确定,
声明时用"..."表示。固定参数和可选参数公同构成一个函数的参数列表。

.具体分析
下面是分析c库中的printf函数,但完全适用与内核printk的分析
三个关键宏:

  1. voidva_start ( va_list arg_ptr, prev_param ); /* ANSI version */ typeva_arg ( va_list arg_ptr, type );   voidva_end ( va_list arg_ptr );   
复制代码


在这些宏中,va就是variableargument(可变参数)的意思;
arg_ptr是指向可变参数表的指针;
prev_param指可变参数表的前一个固定参数;
type为可变参数的类型。
va_list也是一个宏,其定义为typedefchar * va_list,实质上是一char型指针。
char型指针的特点操作对其作用的结果是增1和减1(因为sizeof(char)1)
<1>va_start
(1)定义:

  1. #defineva_start ( ap, v ) ( ap = (va_list)&v + _INTSIZEOF(v) )_INTSIZEOF宏定义为:#define_INTSIZEOF(n) ((sizeof ( n ) + sizeof ( int ) - 1 ) & ~( sizeof(int ) -1 ) )
复制代码


(2)作用:
根据v取得可变参数表的首指针并赋值给ap,方法:最后一个固定参数v的地址+第一个变参对v的偏移地址,然后赋值给ap,这样ap就是可变参数表的首地址。
(3)举例:
如果有一 va函数的声明是voidva_test(char a, char b,char c, …),则它的固定参数依次是a,b,c,最后一个固定参数argNc,因此就是va_start(arg_ptr,c)。  

<2>va_arg
(1)定义:

  1. #defineva_arg(list, mode) ((mode *)(list = (char*) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) & (__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]
复制代码


(2)作用:
指取出当前 arg_ptr所指的可变参数并将ap指针指向下一可变参数
<3>va_end
(1)定义为:
#defineva_end ( list )   
(2)作用:
结束可变参数的获取。va_end( list )实际上被定义为空,没有任何真实对应的代码,用于代码对称,与va_start对应。

.实践
<1>怎样得到可变参数个数?归纳起来有三种办法:
(1)函数的第一个参数,指定后续的参数个数,func(intnum,...)
(2)根据隐含参数,判断参数个数,printf系列的,通过字符串中%的个数判断
(3)特殊情况下(如参数都是不大于0xFFFFint),
可以一直向低处访问堆栈,直到
返回地址。

<2>举例说明三种情况:
(1)情况1
  1. #include<stdio.h>
  2. #include<stdarg.h>
  3. void VariableFunc(int prev_param, ...)
  4. {
  5. va_list
  6. arg_ptr;                                       
  7. //可变参数表的首指针
  8. va_start(arg_ptr,
  9. prev_param); //取得可变参数表的首地址并赋给arg_ptr
  10. for(int
  11. i=0;i<prev_param;i++)
  12. {
  13.     int
  14.     ParamValue;
  15.     ParamValue=va_arg(arg_ptr,
  16. int);//取出当前arg_ptr所指的可变参数并将ap指针指向下一可变参数
  17. printf("这是第%d个可变参数,值:%d,类型:int\n",i+1,ParamValue);
  18. }
  19. va_end(arg_ptr);//执行清理工作
  20. }
复制代码

(2)情况2
  1. #include<stdio.h>
  2. #include<stdarg.h> //包含些头文件
  3. #include<string>
  4. using namespace std;
  5. //模仿printf函数,写一个printk函数
  6. void printk(char* prev_param, ...)
  7. {
  8. int
  9. j = 0;
  10. va_list
  11. arg_ptr; //可变参数表的首指针
  12. va_start(arg_ptr,prev_param);
  13. //取得可变参数表的首地址
  14. string
  15. FormatStr(prev_param); //保存格式化的字符串
  16. int
  17. InsertPos;
  18. //当在固定参数中找到%符号时:
  19. while(-1!=(InsertPos=FormatStr.find("%")))
  20. {
  21.     //根据%后面的字符分别进行处理        
  22.     if(FormatStr[InsertPos+1]=='d')
  23.     //%号后是'd'就转为字符再插入
  24.     FormatStr
  25.     {
  26.      char
  27.      buf[15];
  28.      int
  29.      IntValud=va_arg(arg_ptr,int); //从可变参数列表中获得数据
  30.      itoa(IntValud,buf,10);                           
  31.      //Int 转string并保存在buf
  32.      FormatStr.erase(InsertPos,2);//擦除两个字符%d
  33.      FormatStr.insert(InsertPos,buf);
  34. //插入Int值到FormatStr
  35.     }            
  36.     else
  37. if(FormatStr[InsertPos+1]=='s') ////%号后是's'就直接将字符串插入FormatStr
  38.     {
  39.      FormatStr.erase(InsertPos,2);   
  40. FormatStr.insert(InsertPos,va_arg(arg_ptr,char*));
  41.     }
  42. }
  43. printf("%s\n",FormatStr.c_str());
  44. //打印出处理后的FormatStr
  45. va_end(arg_ptr);//执行清理工作
  46. }
  47. void main()
  48. {
  49. printk("show
  50. you how %s %s work %d","printf","function",88);
  51. }
复制代码

(3)情况3
  1. #include   <stdio.h>   
  2. #include   <stdarg.h>     
  3. struct   T_Progs{     
  4. int   x;     
  5. int   y;   
  6. };
  7. void   func(T_Progs    *tProgs,...)     
  8. {  
  9. int   total    =    0;     
  10. va_list   ap;     
  11. T_Progs   *p;     
  12. va_start(ap,
  13.    tProgs);     
  14. p  =    tProgs;     
  15. printf("x[%d]=%d\n",total,p->x);
  16. printf("y[%d]=%d\n",total,p->y);
  17. total++;
  18. while
  19.    (p    =    (va_arg(ap,T_Progs*)))      
  20. {  
  21.     printf("x[%d]=%d\n",total,p->x);
  22.     printf("y[%d]=%d\n",total,p->y);
  23.     total ++;   
  24. }  
  25. va_end(ap);
  26. printf("参数个数:%d\n",total);
  27. }  
  28. void   main(void)   
  29. {
  30. T_Progs
  31.    test1,test2;     
  32. test1.x   =    1;test2.x    =    3;     
  33. test1.y   =    2;test2.y    =    4;     
  34. func(&test1,&test2,NULL);
  35. }
复制代码


四.最简单的移植步骤
<1>我们许多选择:
(1)移植linux的printf,版本越新越难移植,但是功能也越强大
(2)移植uboot的printf,实际uboot也是移植到内核的
(3)完全自己编写,但是功能比较弱
在保证整个裸机其他代码部分没有任何问题,且编译器也没有任何问题的情况下,上述三种方法都是可行的。
下面我们只是直接采用韦东山老师移植好的printf相关的库文件,他的办法是移植2.4内核版本的printf功能
<2>拷贝附件里相关库文件到裸机代码根目录
<3>修改makefile如附件所示,必须严格按照makefile里的相关设置
<4>make 编译并测试
测试代码如下:

  1. void test_printf(void)
  2. {   
  3.      char *p="this is %s test";
  4.      char c='H';  
  5.      int d=-256;   
  6.      int k=0;   
  7.      printf("testing printf\n");
  8.      printf("test string :::        %s\ntest char ::: %c\ntest digit ::: %d\ntest X ::: %x\ntest unsigned ::: %u\ntest zero ::: %d\n",p,c,d,d,d,k);
  9. }
复制代码




我要做linux驱动工程师
回复

使用道具 举报

14

主题

68

帖子

211

积分

版主

Rank: 7Rank: 7Rank: 7

积分
211
 楼主| 发表于 2012-4-17 15:00:00 | 显示全部楼层
内核太多东西可以让我们借鉴了,建议大家直接去移植内核的printk
我要做linux驱动工程师
回复 支持 反对

使用道具 举报

4

主题

15

帖子

17

积分

新手上路

Rank: 1

积分
17
发表于 2012-7-29 17:24:00 | 显示全部楼层
你好,师兄,问一下我裸机编译printf出来这种提示
arm-linux-gcc -Wall -O2 -c -o main.o main.c
arm-linux-ld -Tuart.lds -o uart_elf head.o init.o shoufa.o main.o
main.o(.text+0xc): In function `main':
: undefined reference to `printf'
make: *** [uart.bin] Error 1

这是我的代码,请问我该怎么改,才能用printf
#include <stdio.h>

int main()
{                                                                                                  char c= 'a';                                                                           printf("%c\n", c);
    while(1)
    {
        
      ;                }

    return 0;
}
回复 支持 反对

使用道具 举报

技术支持
在线咨询
咨询热线
0755-86200561
微信扫一扫
获取更多资讯!

Archiver|小黑屋|百问linux嵌入式论坛     

GMT+8, 2018-11-18 14:38 , Processed in 0.344481 second(s), 22 queries , File On.

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc. Template By 【未来科技】【 www.wekei.cn 】

快速回复 返回顶部 返回列表