为什么我的 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);
}
等等
我需要为学校项目重新创建 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);
}
等等