0

我正在为我正在为类分配工作的引导加载程序创建自己的 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:,这是不正确的。我试过只用整数打印,效果很好,但是当我尝试打印无符号长整数时,我遇到了问题。

这是我的代码:

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 = "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 short 更改为 unsigned long,并且事情已更改为打印HI! :L: :0: :0: :: :: :1:

4

5 回答 5

4

这里有一个提示:

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

一路走来,您使用较短的类型。例如,我会检查您的使用情况u16

于 2011-01-30T21:53:26.653 回答
3

你在为什么架构编程?

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

因此,让我们假设 x86 处于 16 位模式:

看起来您正在使用 *ip 来处理参数,因为它们被推入堆栈。由于 ip 是指向 long(32 位数据类型)的指针,因此当您执行 ip++ 时,您将指针所保存的实际值增加 4,例如如果 *ip = 0x1234 然后 *(ip+1) = 0x1238。因此,如果您将 ip++ 用于 16 位整数,那么每次执行 ip++ 时都会跳过一个整数,因为整数只有 2 个字节(16 位)。一种可能的解决方案是使用 void * 作为 ip,然后将 sizeof(data type) 添加到 ip;即如果你打印一个int,那么:

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

或者对于无符号长:

ip += sizeof(unsigned long);

但是,如果没有关于您正在编程的确切架构以及您的编译器正在使用什么 ABI 的更具体细节,我只能粗略推测。

我希望这有帮助。

问候,亚历克斯

于 2011-01-30T23:49:26.437 回答
2

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

现代 C 还需要具有...可变参数函数的完整原型。

于 2011-01-30T21:53:20.583 回答
1

您的 rpi 函数使用 u16(我猜是无符号短)作为数据类型,对于值为 42949672 的整数而言,它太小了。

于 2011-01-30T21:51:44.617 回答
1

在尝试这么多 % 参数之前,您最好编写和验证更基本的测试用例。

于 2011-01-30T22:19:51.363 回答