如何在c中实现自己的printf

如何在c中实现自己的printf,c,C,我正在重新创建C函数printf,在%之后,函数转到下面的if语句,如果我不知道第二个参数的数据类型,如何使用va_arg()访问传递给我的printf的参数进行打印 if (str[a] == 'c' || str[a] == 'd' || str[a] == 's') print_char(str[a], va_arg(arg, )); 这是我的原始代码,但是太长了,我最多只能写25行。这就是为什么我想将%之后的字符传递给一个函数,然后该函数将打印存储在参数中的值 void ft_

我正在重新创建C函数
printf
,在
%
之后,函数转到下面的if语句,如果我不知道第二个参数的数据类型,如何使用
va_arg()
访问传递给我的
printf
的参数进行打印

if (str[a] == 'c' || str[a] == 'd' || str[a] == 's')
    print_char(str[a], va_arg(arg, ));
这是我的原始代码,但是太长了,我最多只能写25行。这就是为什么我想将
%
之后的字符传递给一个函数,然后该函数将打印存储在参数中的值

void ft_printf(char *fmt, ...)
{
    char *s;
    unsigned int i;
    char *str;
    int a;

    va_list arg;
    va_start(arg, fmt);
    str = fmt;
    a = 0;
    while (str[a])
    {
        while (str[a] == ' ' || str[a] == '\t')
            a++;

        while (str[a] != '%')
        {
            ft_putchar(str[a]);
            a++;
        }
        a++;
        if (str[a] == 'c')
        {
            i = va_arg(arg, int);
            ft_putchar(i);
        }
        else if (str[a] == 'd')
        {
            i = va_arg(arg, int);
            ft_putchar(i);
        }
        else if (str[a] == 's')
        {
            s = va_arg(arg, char *);
            ft_putstr(s);
        }
        a++;
    }
    va_end(arg);
}

首先,您应该实现
printf
作为对
vfprintf()
的调用,按值传递
va_列表

ft_vfprintf()
函数中,可以通过函数指针数组将
va_列表
按值传递给特定于每种格式的函数,但是,它们无法正确更新调用方中的
va_列表
,并且您无法以可移植的方式传递指向
va_列表
的指针,因为这种类型可能被定义为数组。然而,这些函数可以将
va_列表
与其他信息一起递归地继续解析

这种方法称为连续编译,其中每个函数调用下一个函数并返回其结果。如果编译器能够有效地处理这些尾部调用,那么具有许多参数的长格式字符串的堆栈深度可能会很小,否则它仍然在合理的范围内:每个转换规范有两个递归调用

我怀疑这是42岁或Epitech的人对你的期望,但这是一种用小功能实现
printf
的方法。但是请注意,完整的实现并不简单,因为格式规范可能还包含标志、修饰符、宽度和精度参数,但如果有额外的状态信息,它仍然是可行的

下面是一个简单的例子:

#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;
}
#包括
#包括
int ft_putchar(int c){
chara[1];
a[0]=(字符)c;
返回写入(0,a,1);
}
静态整数英尺打印辅助(常量字符*fmt,变量列表ap,整数长度);
静态整型打印(常量字符*fmt,变量列表ap,整型){
int c=va_arg(ap,int);
普查尔堡(c);
返回ft_printf_aux(fmt、ap、len+1);
}
静态整数ft_putnum(无符号长n,无符号整数基,常量字符*位数){
int res=1;
如果(n>=base)
res+=英尺单位(n/基数、基数、位数);
ft_putchar(数字[n%基数]);
返回res;
}
静态整型打印(常量字符*fmt,变量列表ap,整型){
int n=va_arg(ap,int);
无符号长u;
if(n<0){
ft_putchar('-');
len++;
u=-(无符号)n;
}否则{
u=n;
}
len+=英尺(u,10,“0123456789”);
返回ft_printf_aux(fmt、ap、len);
}
静态整型打印(常量字符*fmt,变量列表ap,整型){
无符号整数n=va_arg(ap,无符号整数);
len+=ft_putnum(n,8,“01234567”);
返回ft_printf_aux(fmt、ap、len);
}
静态整型整型打印(常量字符*fmt,变量列表ap,整型长度){
无符号整数n=va_arg(ap,无符号整数);
len+=ft_putnum(n,10,“0123456789”);
返回ft_printf_aux(fmt、ap、len);
}
静态整型打印(常量字符*fmt,变量列表ap,整型){
无符号整数n=va_arg(ap,无符号整数);
len+=ft_putnum(n,16,“0123456789abcdef”);
返回ft_printf_aux(fmt、ap、len);
}
静态整型打印(常量字符*fmt,变量列表ap,整型){
无符号整数n=va_arg(ap,无符号整数);
len+=ft_putnum(n,16,“0123456789ABCDEF”);
返回ft_printf_aux(fmt、ap、len);
}
静态整型打印(常量字符*fmt,变量列表ap,整型){
常量字符*s=va_arg(ap,常量字符*);
如果(s==NULL){
s=“(空)”;
}
而(*s){
ft_putchar(*s++);
len++;
}
返回ft_printf_aux(fmt、ap、len);
}
typedef int(*打印发送)(常量字符*fmt,变量列表ap,int len);
静态ft_打印_发送_fconst ft_打印_发送[256]={
[c']=ft_print_c,
['d']=ft\u print\u d,
[i']=ft\u print\u d,
[o']=ft_print_o,
['u']=ft\u print\u,
['x']=ft_print_x,
['X']=ft_print_X,
['s']=ft_print_s,
};
静态整型打印辅助(常量字符*fmt,变量列表ap,整型){
INTC;
while(*fmt){
c=(无符号字符)*fmt++;
如果(c!=“%”){
普查尔堡(c);
len++;
}否则{
c=(无符号字符)*fmt++;
如果(ft_打印_发送[c]==NULL){
如果(c=='\0')
打破
普查尔堡(c);
len++;
}否则{
返回ft_打印发送[c](fmt、ap、len);
}
}
}
回程透镜;
}
int ft_vprintf(常量字符*fmt,变量列表ap){
返回ft_printf_aux(fmt,ap,0);
}
int ft_printf(常量字符*fmt,…){
va_列表ap;
int n;
va_启动(ap、fmt);
n=ft_printf_aux(fmt,ap,0);
va_端(ap);
返回n;
}
内部主(空){
ft_printf(“Hello word”);
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);
返回0;
}

您可以从格式字符串中辨别数据类型<例如,code>%f
是一个浮点,因此当您这样做时,您只需从
va_列表中获得一个浮点。如果使用此链接中演示的方法,我必须将%后面的字符和存储在该字符中的值传递给函数。代码变得太长了,这就是为什么我要将is传递给函数的原因不可能在25行以下编写printf函数
printf()
有许多可能的格式标记,您只需要访问
man-s3printf
。您可以使用
vprintf()
实现printf,但这可能不允许@JohnsonMizzyDubula的可能提示:这个答案对您有帮助吗?