2011-01-30 99 views
0

我正在为引导加载程序创建自己的prinf()我正在处理类分配,这意味着我必须使用BCC编译器,并且我不能使用系统库因为它们不存在。我有能力使用在汇编中设计的putc()函数,并且字符串库函数strcmp等可以根据需要帮助我。Linux C创建无头文件库的自定义printf函数

我似乎遇到了逻辑问题。

如果我在Linux(CC)编译测试文件定义该:

int a = 0; 
int b = 1; 
int i1 = 0; 
int i2 = 1; 
unsigned long x = 42949672; 
printf("\nHI! :%d: :%d: :%d: :%d: :%d: :%d:\n", x,a,b,i1,i2,x); 

我可以运行./a.out和我接收HI! :42949672: :0: :1: :0: :1: :42949672:这是正确的。

我创建了自己的printf函数,当我看到打印的东西时,我看到HI! :23592: :655: :0: :1: :0: :1:,这是不正确的。我试过仅用整数打印并且工作正常,但是当我尝试打印未签名的长整型时,我遇到了问题。

这里是我的代码:

void prints(s) char *s; 
{ 
     int i; 
     for(i=0; i<strlen(s); i++) 
       putc(s[i]); 
} 

void gets(s) char *s; 
{ 
     //LEC9.pdf 
     while((*s=getc()) != '\r') 
     { 
       putc(*s++); 
     } 
*s = '\0'; 
} 

//EXAMPLE CODE 
char *ctable = "ABCDEF"; 
int rpi(x, BASE) unsigned long x; int BASE; 
{ 
     char c; 
     if (x) 
{ 
       c = ctable[x % BASE]; 
       rpi(x/BASE, BASE); 
       putc(c); 
     } 
return 0; 
} 

void printc(ip) unsigned long; 
{ 
     putc(ip); 
} 
int printd(ip) unsigned long; 
{ 
     if(ip < 0) 
     { 
       putc('-'); 
       ip = -ip; 
     } 
if(ip == 0) 
{ 
    putc('0'); 
    return 0; 
} 
rpi(ip, 10); 
} 
void printx(ip) unsigned long; 
{ 
     prints("0x"); //PUT OR OUTPUT LOOK LIKE INT 
     rpi(ip, 16); 
} 
int printl(ip) unsigned long; 
{ 
if(ip == 0) 
{ 
    putc('0'); 
    return 0; 
} 
     rpi(ip, 10); 
     putc('L'); 
} 
void printf(fmt) char *fmt; 
{ 
     char *cp;    //POINTER TO LOOP THROUGH 
     unsigned long *ip;  //POINTER FOR 

     cp = fmt;    //SET POINTER TO START POINTER {FMT} 
     ip = &fmt+1;   //Board says &fmt:but will not work without +1 

     while(*cp) 
     { 
       //IF C != % 
       if(*cp != '%') 
       { 
         printf("%c", *cp); 
         if(*cp == '\n') 
         { 
           //putc('\n'); //implied 
           putc('\r'); 
         } 
         cp++; 
         continue; //NEXT CHAR 
       } 
       else 
       { 
         //MOVE ONE CHARACTER (%{x}) SO WE CAN GET x 
         cp++; 
         switch(*cp) 
         { 
           case 'c': 
             printc(*ip); 
             break; 
           case 's': 
             prints(*ip); 
             break; 
           case 'd': 
             printd(*ip); 
             break; 
           case 'x': 
             printx(*ip); 
             break; 
           case 'l': 
             printl(*ip); 
             break; 
           default: 
             break; 
         }    } 
       cp++; 
       ip++; 
     } 
} 

任何人有任何建议,因为我一直在坚持,需要一些帮助。

EDIT(下午2点06分):我已经改变了我所有的U16 /无符号短为unsigned long,情况发生了改变印刷HI! :L: :0: :0: :: :: :1:

+1

不要编写没有原型的代码! `printc(ip)`后面的'unsigned short;`什么也不做; `ip`仍然是一个`int`。 – 2011-01-30 22:01:53

+1

行int rpi(x,BASE)无符号32 x; int BASE;`不会在正统C编译器下编译。 – 2011-01-30 22:05:48

+0

我使用bcc编译器,因为这个程序是我们OS开发类的一部分,我们使用ext2图像来缓慢构建我们自己的操作系统。它编译使用bcc -c main.c,as86 -o main.o main.s,ld86 -s main.o /usr/lib/bcc/libc.a -o u.out – user591162 2011-01-30 22:09:03

回答

3

你在编程什么架构?

如果您正在为x86编写引导加载程序,那么您的引导加载程序将首先处于16位模式。因此,当编译器发出一条推送指令时,我会猜测它传递了printf()函数的参数,它将默认推送16位数据。长数据类型将是一个专门发布的指令(或两个)将所有32位压入堆栈,假设int为16位,长为32位(对于16位模式编译器,这不是一个不合理的假设,我不认为)。

所以,让我们假设在16位模式下的x86:

这将您正在使用的IP *解决的论点,因为它们压入堆栈出现。由于ip是一个指向long(32位数据类型)的指针,因此在执行ip ++时,您将指针保持的实际值递增4,如if * ip = 0x1234,则*(ip + 1)= 0x1238。因此,如果您使用ip ++作为16位整数,则每次执行ip ++时都跳过一个整数,因为整数只有2个字节(16位)。一个可能的解决方案是使用void *作为ip,然后将sizeof(数据类型)添加到ip;也就是说,如果你打印一个int,这样的:

void *ip = &(fmt + 1); /* Skip over fmt. */ 
... 
ip += sizeof(int); 

或为一个unsigned long:

ip += sizeof(unsigned long); 

然而,如果没有约你是编程的和什么ABI编译器的具体架构更具体的细节正在使用,我只能疯狂地推测。

我希望这会有所帮助。

Regards, Alex

1

你RPI功能通过U16(无符号短我猜的)数据类型这是远远太小与价值42949672.

+0

我应该看到,但将u16更改为unsigned long会打印出“HI!:P::: 1:1:0:1:1”,但它似乎仍然会以不同顺序移动不应该是。任何其他提示可能有帮助? – user591162 2011-01-30 21:58:42

2

假设“BCC”的编译器是至少有些现代的,你应该使用它的<stdarg.h>va_startva_argva_end访问可变参数的整数。

现代C还需要一个完整的原型与...可变参数函数。

+0

问题是我正在写一个引导装载程序,所以头文件库不存在,这意味着stdarg,stdio等不存在。我只能使用putc和基本的字符串函数。 – user591162 2011-01-30 22:00:02

4

这里有一个提示:

>>> hex(42949672) 
'0x28f5c28' 
>>> hex(23592) 
'0x5c28' 

沿着您使用较短的类型的方式某处。例如,我会检查您使用的u16

1

在尝试使用如此多的%参数之前,最好先编写和验证更基本的测试用例。