C语言 在我的函数中实现va_arg的问题

bqf10yzr  于 2023-10-16  发布在  其他
关注(0)|答案(1)|浏览(92)

我目前正在调试我的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:lalalala| 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

mqkwyuun

mqkwyuun1#

来自C11 7.16变量参数<stdarg.h>:(强调和格式化我的)
声明的类型为

va_list

其是适合于保存宏X1 m0n1x、X1 m1n1x、X1 m2n1x和X1 m3n1x所需的信息的完整对象类型。如果需要访问可变参数,则被调用的函数应声明一个类型为va_list的对象(在本小节中通常称为 ap)。对象 ap 可以作为参数传递给另一个函数;如果该函数用参数ap调用va_arg宏,则调用函数中 ap 值是不确定的,且应在进一步引用 ap 之前传递给va_end宏。

允许创建指向va_list的指针并将该指针传递给另一个函数,在这种情况下,原始函数可以在其他函数返回后进一步使用原始列表。
因此,在ft_format返回后,必须在args上调用va_end,以将其从不确定状态恢复。
但是,C11 7.16.1.3 va_end宏也有这样的说法:* (强调和格式化我的)*
va_end宏有助于从其变量参数列表被va_start宏的扩展引用的函数或包含va_copy macro扩展的函数(初始化va_listap)正常返回。**va_end宏可能会修改 ap,使其不再可用(不需要va_startva_copy宏重新初始化)。**如果没有相应的va_startva_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]);

return (ft_putchar(va_arg(*args, int)));

相关问题