为什么我的 printf 函数中的可变参数函数不起作用?

Why do my variadic functions in my printf function not work?

我需要为学校项目重新创建 printf 函数。我当前的函数运行完美,除非有两个参数。

如果我执行以下操作:ft_printf("%c%c", 'a', 'b');

它将打印 aa,而不是 ab

如果我执行以下操作:ft_printf("%c%d", 't', 29);

它不会像预期的那样打印 t29。 相反,它将打印 t116,因为它确实检测到我想打印一个 int,但没有使用正确的参数(它将“t”转换为其 ascii 值 (116))。

我在下面包含了我的主要 printf 函数的代码,ft_analysis 函数(查找标志),ft_utilities_one 函数(它有一些基本函数,比如 putchar () 例如) 以及我用来解析作为主要参数给出的字符串的解析函数。由于代码较多,我只以char打印函数(ft_c_craft)为例。如果您需要更清楚地了解如何使用这些函数,您可以找到 here my printf repository.

ft_printf.c

int ft_printf(const char *str, ...)
{
    t_list  box;
    va_list argptr;

    va_start(argptr, str);
    ft_parser(argptr, (char *)str, &box);
    va_end(argptr);
    return (box.len);
}

ft_parser.c

static void ft_craft1(va_list argptr, t_list *box)
{
    if (box->type == 'c')
        ft_c_craft(va_arg(argptr, int), box);
    else if (box->type == 's')
        ft_s_craft(va_arg(argptr, char *), box);
    else if (box->type == 'd' || box->type == 'i')
        ft_di_craft(va_arg(argptr, int), box);
}

static void ft_craft2(va_list argptr, t_list *box)
{
    if (box->type == 'u')
        ft_u_craft(va_arg(argptr, unsigned int), box);
    else if (box->type == 'x')
        ft_xx_craft(va_arg(argptr, int), 0, box);
    else if (box->type == 'X')
        ft_xx_craft(va_arg(argptr, int), 1, box);
    else if (box->type == 'p')
        ft_p_craft(va_arg(argptr, unsigned long long), box);
}

static void ft_type_selector(va_list argptr, t_list *box)
{
    if (box->type == 'c' || box->type == 's' || box->type == 'd'
            || box->type == 'i')
        ft_craft1(argptr, box);
    else
        ft_craft2(argptr, box);
}

void        ft_parser(va_list argptr, char *str, t_list *box)
{
    int i;

    i = 0;
    while (str[i] != '[=11=]')
    {
        if (str[i] == '%' && str[i + 1] != '%')
        {
            ft_analysis(&str[++i], box);
            while (ft_strchr("cspdiuxX", str[i]) == NULL)
                i++;
            if (ft_strchr("cspdiuxX", str[i]))
                box->type = str[i];
            ft_type_selector(argptr, box);
        }
        else if (str[i] == '%' && str[i + 1] == '%')
            ft_putchar(str[++i], box);
        else
            ft_putchar(str[i], box);
        i++;
    }
}

ft_analysis.c

static void ft_precision(char *str, t_list *box)
{
    box->precision = 0;
    while (*str != '[=12=]')
    {
        if (*str == '.')
        {
            box->precision = ft_atoi_alpha(++str);
            return ;
        }
        str++;
    }
    return ;
}

static void ft_width(char *str, t_list *box)
{
    box->width = 0;
    while (*str != '[=12=]' && *str != '.')
    {
        if (*str >= '0' && *str <= '9')
        {
            box->width = ft_atoi_alpha(str);
            return ;
        }
        str++;
    }
    return ;
}

static void ft_flag(char *str, t_list *box)
{
    box->fzero = 0;
    box->fplus = 0;
    box->fminus = 0;
    box->fspace = 0;
    while (*str != '[=12=]' && (!(*str >= '1' && *str <= '9')))
        if (*str++ == '0')
            box->fzero += 1;
    else if (ft_strchr(str, '+'))
        box->fplus += 1;
    else if (ft_strchr(str, '-'))
        box->fminus += 1;
    else if (ft_strchr(str, ' '))
        box->fspace += 1;
    return ;
}

void        ft_analysis(char *str, t_list *box)
{
    ft_precision(str, box);
    ft_width(str, box);
    ft_flag(str, box);
}

ft_c_craft.c

static void ft_print_char(char c, t_list *box)
{
    if (box->fminus == 1)
    {
        ft_putchar(c, box);
        ft_super_putchar(box->width - 1, ' ', box);
        return ;
    }
    else if (box->fzero == 1)
        ft_super_putchar(box->width - 1, '0', box);
    else if (box->fminus == 0)
        ft_super_putchar(box->width - 1, ' ', box);
    ft_putchar(c, box);
    return ;
}

void    ft_c_craft(char c, t_list *box)
{
    if (box->width > 1)
        ft_print_char(c, box);
    else
        ft_putchar(c, box);
}

ft_utilities_one.c

void    ft_putchar(char c, t_list *box)
{
    write(1, &c, 1);
    box->len += 1;
}

void    ft_putstr(char *str, t_list *box)
{
    while (*str != '[=14=]')
    {
        write(1, str++, 1);
        box->len += 1;
    }
}

void    ft_putstr_precision(char *str, t_list *box)
{
    int i;

    i = box->precision;
    while (*str != '[=14=]' && i-- > 0)
    {
        write(1, str++, 1);
        box->len += 1;
    }
}   

void    ft_super_putchar(int len, char c, t_list *box)
{
    while (len-- > 0)
    {
        write(1, &c, 1);
        box->len += 1;
    }
}

long    ft_atoi_alpha(const char *nptr)
{
    long    result;

    result = 0;
    while (*nptr && ((*nptr >= 9 && *nptr <= 13) || *nptr == ' '))
        nptr++;
    if (*nptr == '-' || *nptr == '+')
        nptr++;
    while (*nptr && *nptr >= '0' && *nptr <= '9')
        result = result * 10 + (*nptr++ - '0');
    return (result);
}

像这个简单的例子一样使用switch() case

int ts_formatstring(char *buf, const char *fmt, va_list va)
{
    char *start_buf = buf;
    while(*fmt)
    {
        /* Character needs formating? */
        if (*fmt == '%')
        {
            switch (*(++fmt))
            {
              case 'c':
                *buf++ = va_arg(va, int);
                break;
              case 'd':
              case 'i':
                {
                    signed int val = va_arg(va, signed int);
                    if (val < 0)
                    {
                        val *= -1;
                        *buf++ = '-';
                    }
                    ts_itoa(&buf, val, 10);
                }
                break;
              case 's':
                {
                    char * arg = va_arg(va, char *);
                    while (*arg)
                    {
                        *buf++ = *arg++;
                    }
                }
                break;
              case 'u':
                    ts_itoa(&buf, va_arg(va, unsigned int), 10);
                break;
              case 'x':
              case 'X':
                    ts_itoa(&buf, va_arg(va, int), 16);
                break;
              case '%':
                  *buf++ = '%';
                  break;
            }
            fmt++;
        }
        /* Else just copy */
        else
        {
            *buf++ = *fmt++;
        }
    }
    *buf = 0;

    return (int)(buf - start_buf);
}

PS 不是 mycode,它来自 atollic - 用于示例目的。 Sme 潜在的 UB。

If I do the following: ft_printf("%c%c", 'a', 'b');

it will print aa, instead of ab.

If I do the following: ft_printf("%c%d", 't', 29);

it will not print t29 like it's supposed to. Instead, it will print t116 as it does detect that I would like to print an int, but doesn't use the right argument (it converts "t" in its ascii value (116)).

显然你没有进步,总是使用第一个参数,这是因为你按值给了 va_list,所以你使用了它的副本并且你无法在参数列表中取得进展。直接给指针

ft_printf

ft_parser(&argptr, (char *)str, &box);

和:

static void ft_craft1(va_list *argptr, t_list *box)
{
    if (box->type == 'c')
        ft_c_craft(va_arg(*argptr, int), box);
    else if (box->type == 's')
        ft_s_craft(va_arg(*argptr, char *), box);
    else if (box->type == 'd' || box->type == 'i')
        ft_di_craft(va_arg(*argptr, int), box);
}

等等