我的函数中 va_arg 的实现出现问题

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

我目前正在为学校调试我的 printf 项目,基本上我只需要重做该功能,但我遇到了一个我无法理解的问题。

这是我的代码:

#include "ft_printf.h"

int ft_putchar(int c)
{
    write(1, &c, 1);
    return (1);
}

int ft_format(va_list args, const char format)
{
    if (format == 'c')
        return (ft_putchar(va_arg(args, int)));
    return (-1);
}

int ft_printf(const char *format, ...)
{
    size_t  i;
    int     print_length;
    va_list args;

    i = 0;
    print_length = 0;
    va_start(args, format);
    while (format[i])
    {
        if (format[i] == '%')
        {
            i++;
            if (format[i] != '\0')
            {
                print_length += ft_format(args, format[i]);
            }
        }
        else
            print_length += ft_putchar(format[i]);
        i++;
    }
    va_end(args);
    return (print_length);
}

int main(void)
{
    ft_printf("l%cl%cl%cl%c\n", 'a', 'b', 'c', 'd');
    printf("l%cl%cl%cl%c\n", 'a', 'b', 'c', 'd');
}

结果:

ft_printf:拉拉拉拉 | printf : lalblcld

我无法理解为什么当我尝试打印许多参数时它不能正常工作,所以如果有人可以帮助我找出问题所在..

我尝试过的:

我尝试添加 va_arg(args, int);调用 ft_format 后,它工作正常!但我仍然不明白为什么这种情况没有直接在我的 ft_format 函数中处理?

int ft_printf(const char *format, ...)
{
    size_t  i;
    int     print_length;
    va_list args;

    i = 0;
    print_length = 0;
    va_start(args, format);
    while (format[i])
    {
        if (format[i] == '%')
        {
            i++;
            if (format[i] != '\0')
            {
                print_length += ft_format(args, format[i]);
                                a_arg(args, int);
            }
        }
        else
            print_length += ft_putchar(format[i]);
        i++;
    }
    va_end(args);
    return (print_length);
}

输出:

ft_printf:lalblcld | printf : lalblcld

c printf
1个回答
0
投票

来自 C11 7.16 变量参数 (强调并格式化我的)

声明的类型是

    va_list

这是一个完整的对象类型,适合保存宏

va_start
va_arg
va_end
va_copy
所需的信息。如果需要访问不同的参数,则被调用的函数应声明一个具有类型 va_list 的对象(在本子条款中通常称为
ap
)。 对象 ap 可以作为参数传递给另一个函数;如果该函数使用参数 ap 调用
va_arg
宏,则调用函数中 ap 的值是不确定的,并且应在进一步引用
ap
之前传递给 va_end 宏。

允许创建一个指向

va_list
的指针并将该指针传递给另一个函数,在这种情况下,原始函数可以在另一个函数返回后进一步使用原始列表。

因此,在

ft_format
返回后,必须在
va_end
上调用
args
以将其从不确定状态恢复。

但是,C11 7.16.1.3 va_end 宏也有这样的说法:(强调并格式化我的)

va_end
宏有助于从其变量参数列表由
va_start
宏的扩展引用的函数或包含
va_copy macro
扩展的函数正常返回,该函数初始化了
va_list
ap
va_end
宏可能会修改ap,使其不再可用(无需由
va_start
va_copy
宏重新初始化)。
如果没有相应的
va_start
va_copy
调用宏,或者如果在返回之前未调用
va_end
宏,则行为未定义。

据我所知,您有两种选择:

使用

va_copy
创建
va_list
对象当前状态的副本

if (format[i] != '\0')
{
    va_list tmp;
    va_copy(tmp, args);
    print_length += ft_format(tmp, format[i]);
    va_end(tmp);
}

并将该对象传递给

ft_format

或者,将

ft_format
定义为

int ft_format(va_list *args, const char format)

并将其传递给您的

va_list
对象

print_length += ft_format(&args, format[i]);
© www.soinside.com 2019 - 2024. All rights reserved.