Linux C创建没有头库的自定义printf函数

我正在为引导加载器创建自己的prinf()我正在为类分配工作,这意味着我必须使用BCC编译器,因为它们不存在所以我不能使用系统库。我有能力使用汇编中设计的putc()函数和字符串库函数strcmp等来帮助我。 我似乎遇到了一个逻辑问题。 如果我在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:
,这是不正确的。我只尝试使用整数打印并且工作正常,但是当我尝试打印unsigned long时,我遇到了问题。 这是我的代码:
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 = '';
}

//EXAMPLE CODE
char *ctable = "0123456789ABCDEF";
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++;
        }
}
任何人都有任何提示,因为我被困住了,需要一些帮助。 编辑(下午2:06):我已经将我的所有u16 / unsigned短片更改为无符号长,并且已经改为打印
HI! :L: :0: :0: :: :: :1:
    
已邀请:
您为什么架构编程? 如果您正在为x86编写引导加载程序,那么您的引导加载程序将首先处于16位模式。因此,当编译器发出推送指令时,我猜它会传递printf()函数的参数,它默认会推送16位数据。长数据类型将是一个特殊发出的指令(或两个)将所有32位压入堆栈,这假设int是16位而long是32位(对于16位模式编译器来说,这不是一个不合理的假设,我不认为)。 所以,让我们假设x86在16位模式: 看起来你正在使用* ip来解决参数,因为它们被推入堆栈。因为当你执行ip ++时,ip是指向long(32位数据类型)的指针,所以你将指针保持的实际值增加4,如if * ip = 0x1234则*(ip + 1)= 0x1238。因此,如果您使用ip ++进行16位整数,那么每次执行ip ++时都会跳过一个int,因为整数只有2个字节(16位)。一种可能的解决方案是使用void * for ip,然后将sizeof(数据类型)添加到ip;即如果你打印一个int,那么:
void *ip = &(fmt + 1); /* Skip over fmt. */
...
ip += sizeof(int);
或者对于无符号长:
ip += sizeof(unsigned long);
但是,如果没有关于您正在编程的确切架构以及编译器正在使用的ABI的更多具体细节,我只能疯狂地推测。 我希望这有帮助。 问候, 亚历克斯     
这是一个提示:
>>> hex(42949672)
'0x28f5c28'
>>> hex(23592)
'0x5c28'
在某处你使用较短的类型。例如,我会检查你对
u16
的使用。     
假设“BCC”编译器至少有点现代,你应该使用它的
<stdarg.h>
va_start
va_arg
va_end
来访问变量参数。 现代C还需要一个带有
...
的完整原型用于vararg功能。     
您的rpi函数使用的是u16(无符号短整数),因为数据类型对于值为42949672的整数来说太小了。     
在尝试这么多%的参数之前,最好先编写并验证更基本的测试用例。     

要回复问题请先登录注册