我正在重新创建C函数printf
,在%
之后,该函数转到if语句下面,如果我不知道第二个参数的数据类型如何使用{{1 }}来访问传递给我的va_arg()
的参数以进行打印?
printf
这是我的原始代码,但是太长了,我最多只能将其设置为25行。这就是为什么我想将if (str[a] == 'c' || str[a] == 'd' || str[a] == 's')
print_char(str[a], va_arg(arg, ));
之后的字符传递给一个函数,该函数随后将打印存储在参数
%
答案 0 :(得分:2)
首先,您应该实现printf
作为对vfprintf()
的调用,并按值传递va_list
。
在ft_vfprintf()
函数中,可以通过函数指针数组将va_list
按值传递给特定于每种格式的函数,但是它们不会更新va_list
中的正确地调用方,并且您不能将指针便携地传递到va_list
,因为此类型可能被定义为数组。然而,这些功能可以将va_list
连同其他信息一起继续递归地进行解析。
这种方法称为连续编译,其中每个函数调用下一个函数并返回其结果。如果编译器可以有效地处理这些尾部调用,则带有许多参数的长格式字符串的堆栈深度可能会很小,否则仍在合理的范围内:每个转换规范两次递归调用。
我怀疑这是 42 或 Epitech 的人们对您的期望,但这是一种实现printf
且功能较小的方法。但是请注意,完整的实现非常简单,因为格式规范可能还包含标志,修饰符以及width和precision参数,但是使用其他状态信息仍然可能可行。
这是一个简单的例子:
#include <stdarg.h>
#include <unistd.h>
int ft_putchar(int c) {
char a[1];
a[0] = (char)c;
return write(0, a, 1);
}
static int ft_printf_aux(const char *fmt, va_list ap, int len);
static int ft_print_c(const char *fmt, va_list ap, int len) {
int c = va_arg(ap, int);
ft_putchar(c);
return ft_printf_aux(fmt, ap, len + 1);
}
static int ft_putnum(unsigned long long n, unsigned int base, const char *digits) {
int res = 1;
if (n >= base)
res += ft_putnum(n / base, base, digits);
ft_putchar(digits[n % base]);
return res;
}
static int ft_print_d(const char *fmt, va_list ap, int len) {
int n = va_arg(ap, int);
unsigned long long u;
if (n < 0) {
ft_putchar('-');
len++;
u = -(unsigned)n;
} else {
u = n;
}
len += ft_putnum(u, 10, "0123456789");
return ft_printf_aux(fmt, ap, len);
}
static int ft_print_o(const char *fmt, va_list ap, int len) {
unsigned int n = va_arg(ap, unsigned int);
len += ft_putnum(n, 8, "01234567");
return ft_printf_aux(fmt, ap, len);
}
static int ft_print_u(const char *fmt, va_list ap, int len) {
unsigned int n = va_arg(ap, unsigned int);
len += ft_putnum(n, 10, "0123456789");
return ft_printf_aux(fmt, ap, len);
}
static int ft_print_x(const char *fmt, va_list ap, int len) {
unsigned int n = va_arg(ap, unsigned int);
len += ft_putnum(n, 16, "0123456789abcdef");
return ft_printf_aux(fmt, ap, len);
}
static int ft_print_X(const char *fmt, va_list ap, int len) {
unsigned int n = va_arg(ap, unsigned int);
len += ft_putnum(n, 16, "0123456789ABCDEF");
return ft_printf_aux(fmt, ap, len);
}
static int ft_print_s(const char *fmt, va_list ap, int len) {
const char *s = va_arg(ap, const char *);
if (s == NULL) {
s = "(null)";
}
while (*s) {
ft_putchar(*s++);
len++;
}
return ft_printf_aux(fmt, ap, len);
}
typedef int (*ft_print_dispatch_f)(const char *fmt, va_list ap, int len);
static ft_print_dispatch_f const ft_print_dispatch[256] = {
['c'] = ft_print_c,
['d'] = ft_print_d,
['i'] = ft_print_d,
['o'] = ft_print_o,
['u'] = ft_print_u,
['x'] = ft_print_x,
['X'] = ft_print_X,
['s'] = ft_print_s,
};
static int ft_printf_aux(const char *fmt, va_list ap, int len) {
int c;
while (*fmt) {
c = (unsigned char)*fmt++;
if (c != '%') {
ft_putchar(c);
len++;
} else {
c = (unsigned char)*fmt++;
if (ft_print_dispatch[c] == NULL) {
if (c == '\0')
break;
ft_putchar(c);
len++;
} else {
return ft_print_dispatch[c](fmt, ap, len);
}
}
}
return len;
}
int ft_vprintf(const char *fmt, va_list ap) {
return ft_printf_aux(fmt, ap, 0);
}
int ft_printf(const char *fmt, ...) {
va_list ap;
int n;
va_start(ap, fmt);
n = ft_printf_aux(fmt, ap, 0);
va_end(ap);
return n;
}
int main(void) {
ft_printf("Hello word\n");
ft_printf("%cello %s\n", 'H', "word");
ft_printf("%d == 0%o == 0x%x == 0x%X\n", 1, 1, 1, 1);
ft_printf("%d == 0%o == 0x%x == 0x%X\n", 123, 123, 123, 123);
ft_printf("%d == 0%o == 0x%x == 0x%X\n", 0xdead, 0xdead, 0xdead, 0xdead);
return 0;
}