C 中的自定义 _printf 函数中无符号十六进制值的输出不正确

问题描述 投票:0回答:1

我无法从 C 中的自定义 _printf 函数获取正确的输出。该函数应该打印格式化输出,包括无符号的十六进制值。但是,当我尝试在格式字符串中同时使用小写和大写格式说明符时,无符号十六进制值的输出不正确。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <stdarg.h>

#define BUF_SIZE 1024

typedef struct format_s
{
    char *spec;
    int (*handle)(va_list, char *, int *);
} format_t;

void convbase(unsigned long int b, unsigned int bs, char cs, char *buf, int *p)
{
    int i = 0, j;
    unsigned long int temp = b, div = 1;

    while (temp > 0)
    {
        temp /= bs;
        i++;
    }
    for (j = 0; j < (i - 1); j++)
        div *= bs;
    if (cs >= 'a' && cs <= 'z')
    {
        for (; div > 0; div /= bs, *p = *p + 1)
        {
            buf[*p] =  ((b / div) % bs) > 9 ?
                (((b / div) % bs) - 10) + 'a' : (b / div) % bs + '0';
        }
    }
    else
    {
        for (; div > 0; div /= bs, *p = *p + 1)
        {
            buf[*p] = ((b / div) % bs) > 9 ?
                (((b / div) % bs) - 10) + 'A' : ((b / div) % bs) + '0';
        }
    }
}

int handle_x(va_list args, char *buff, int *bufpos)
{
    unsigned int x = va_arg(args, unsigned int), base = 16;
    int count = 1;
    char _case = 'x';

    if (!va_arg(args, unsigned int *))
        return (-1);
    convbase(x, base, _case, buff, bufpos);
    return (count);
}

int handle_X(va_list args, char *buff, int *bufpos)
{
    unsigned int X = va_arg(args, unsigned int), base = 16;
    int count = 1;
    char _case = 'X';

    if (!va_arg(args, unsigned int *))
        return (-1);
    convbase(X, base, _case, buff, bufpos);
    return (count);
}

int (*get_fmt(char spec))(va_list, char *, int *)
{
    format_t formats[] = {
        {"x", handle_x}, {"X", handle_X}, {NULL, NULL}
    };
    int i = 0;

    while (formats[i].spec != NULL)
    {
        if (spec == formats[i].spec[0])
            return (formats[i].handle);
        i++;
    }
    return (NULL);
}

int _printf(const char *format, ...)
{
    int nc = 0, idx, bufpos = 0;
    char *buff = malloc(BUF_SIZE * sizeof(char));
    va_list args;

    if (format == NULL || buff == NULL)
        return (0);
    memset(buff, 0, BUF_SIZE);
    va_start(args, format);
    for (idx = 0; format[idx]; idx++)
    {
        if (format[idx] == '%')
        {
            if (format[idx + 1] == '%')
            {
                buff[bufpos++] = '%';
            }
            else if (format[idx + 1] != '%')
            {
                if (!get_fmt(format[idx + 1])(args, buff, &bufpos))
                {
                    buff[bufpos++] = '%';
                    buff[bufpos++] = format[idx + 1];
                }
            }
            format++;
        }
        else
        {
            buff[bufpos++] = format[idx];
        }
    }
    nc =  write(1, buff, strlen(buff));
    va_end(args);
    return (nc);
}

int main(void)
{
   unsigned int ui;

   ui = (unsigned int)INT_MAX + 1024;
   _printf("Lowercase hexadecimal:[%x]\n", ui);
   printf("Lowercase hexadecimal:[%x]\n", ui);
   _printf("Uppercase hexadecimal:[%X]\n", ui);
   printf("Uppercase hexadecimal:[%X]\n", ui);
   _printf("Unsigned hexadecimal:[%x, %X]\n", ui, ui);
   printf("Unsigned hexadecimal:[%x, %X]\n", ui, ui);
   return (0);
}

我之前编写了 convbase 函数,在计算值在缓冲区中占用的空间后从前面的位置写入缓冲区:

void convbase(unsigned int b, unsigned int base, char _case, char *buf, int *bufpos)
{
    int i, j, rem;
    unsigned long int temp = b, init = *bufpos;

    while (temp > 0)
    {
        temp /= base;
        i++;
    }
    *bufpos = *bufpos +  i;
    if (_case >= 'a' && _case <= 'z')
    {
        for (rem = b % base; i > 0; i--, b /= base, rem = b % base)
        {
            buf[init + i - 1] =  (rem > 9) ?  (rem - 10) + 'a' : rem + '0';
        }
    }
    else
    {
        for (rem = b % base; i > 0; i--, b /= base, rem = b % base)
        {
            buf[init + i - 1] =  (rem > 9) ?  (rem - 10) + 'A' : rem + '0';
        }
    }
}

我得到了错误的输出,现在仍然得到。然后我决定进行转换以从缓冲区的当前位置写入缓冲区,但我仍然得到相同的输出。 我用

gcc -g -Werror -Wall -Wextra -Wno-format -pedantic -std=gnu89 *.c
编译了程序,程序的输出是:

Lowercase hexadecimal:[]
Lowercase hexadecimal:[800003ff]
Uppercase hexadecimal:[]
Uppercase hexadecimal:[800003ff]
Unsigned hexadecimal:[800003ff, ]
Unsigned hexadecimal:[800003ff, 800003FF]

谢谢您的帮助!

c linux pointers buffer function-pointers
1个回答
0
投票

每次使用

va_arg
时,它都会从列表中获取下一个参数。

您在

handle_X
handle_x

中使用了两次

int handle_x(va_list args, char *buff, int *bufpos)
{
    unsigned int x = va_arg(args, unsigned int), base = 16;
    int count = 1;
    char _case = 'x';

    if (!x)
        return (-1);
    convbase(x, base, _case, buff, bufpos);
    return (count);
}

int handle_X(va_list args, char *buff, int *bufpos)
{

    unsigned int X = va_arg(args, unsigned int), base = 16;
    int count = 1;
    char _case = 'X';

    if (!X)
        return (-1);

    convbase(X, base, _case, buff, bufpos);
    return (count);
}

© www.soinside.com 2019 - 2024. All rights reserved.