我目前正在为学校调试我的 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
来自 C11 7.16 变量参数
声明的类型是
va_list
这是一个完整的对象类型,适合保存宏
、va_start
、va_arg
和va_end
所需的信息。如果需要访问不同的参数,则被调用的函数应声明一个具有类型va_copy
va_list
的对象(在本子条款中通常称为ap)。 对象 ap 可以作为参数传递给另一个函数;如果该函数使用参数 ap 调用宏,则调用函数中 ap 的值是不确定的,并且应在进一步引用va_arg
ap之前传递给va_end
宏。
和
允许创建一个指向
的指针并将该指针传递给另一个函数,在这种情况下,原始函数可以在另一个函数返回后进一步使用原始列表。va_list
因此,在
ft_format
返回后,必须在 va_end
上调用 args
以将其从不确定状态恢复。
但是,C11 7.16.1.3 va_end 宏也有这样的说法:(强调并格式化我的)
宏有助于从其变量参数列表由va_end
宏的扩展引用的函数或包含va_start
扩展的函数正常返回,该函数初始化了va_copy macro
ap 。va_list
宏可能会修改ap,使其不再可用(无需由va_end
或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]);