Linux C создает пользовательскую функцию printf без библиотек заголовков - PullRequest
0 голосов
/ 31 января 2011

Я работаю над созданием собственного 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 на unsigned long, и все изменилось на печать HI! :L: :0: :0: :: :: :1:

Ответы [ 5 ]

4 голосов
/ 31 января 2011

Вот подсказка:

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

Где-то по пути вы используете более короткий тип.Я бы проверил ваше использование u16, например.

3 голосов
/ 31 января 2011

Для какой архитектуры вы программируете?

Если вы пишете загрузчик для x86, то ваш загрузчик сначала будет в 16-битном режиме. Таким образом, когда компилятор выдает команду push, которая, как я предполагаю, передает аргументы для функции printf (), он по умолчанию отправляет 16 бит данных. Тип данных long будет специально выданной инструкцией (или двумя), чтобы поместить все 32 бита в стек, при этом предполагается, что int равен 16 битам, а long - 32 бита (что для компилятора 16-битного режима не является необоснованным предположением Не думаю).

Итак, предположим, что x86 в 16-битном режиме:

Может показаться, что вы используете * ip для адресации аргументов, когда они помещаются в стек. Поскольку ip является указателем на long (32-битный тип данных), когда вы делаете ip ++, вы увеличиваете фактическое значение, удерживаемое указателем, на 4, как если бы * ip = 0x1234, тогда * (ip + 1) = 0x1238. Таким образом, если вы используете ip ++ для 16-битных целых чисел, то вы пропускаете int каждый раз, когда делаете ip ++, поскольку целые числа составляют всего 2 байта (16 бит). Возможное решение - использовать void * для ip, а затем добавить sizeof (тип данных) к ip; т.е. если вы печатаете int, то:

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

Или для неподписанного длинного:

ip += sizeof(unsigned long);

Однако, без более подробной информации о точной архитектуре, для которой вы программируете, и о том, какой ABI использует ваш компилятор, я могу только догадываться.

Надеюсь, это поможет.

С уважением, Alex

2 голосов
/ 31 января 2011

Предполагая, что компилятор "BCC" хотя бы несколько современен, вы должны использовать его <stdarg.h> макросы va_start, va_arg и va_end для доступа к аргументам переменной.

Для современного C также требуется полный прототип с ... для функций vararg.

1 голос
/ 31 января 2011

Вам лучше написать и проверить более простые тестовые примеры, прежде чем вы будете использовать столько аргументов%

1 голос
/ 31 января 2011

Ваша функция rpi использует u16 (без знака, я думаю) как тип данных, который слишком мал для целого числа со значением 42949672.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...