16

实际上,我正在尝试printf()使用 varags 在 C 中编写自己的代码。但我没有得到正确的解决方案。谁能帮我吗?

4

6 回答 6

19

在实现 printf() 函数之前,我们必须处理不寻常的问题,即变量参数。我们知道 printf 可以接受除字符串之外的许多参数。所以我们必须使用一个名为 stdarg.h 的标准库来处理这个变量参数问题。在这个实现上下文中,我们不需要学习整个 stdarg.h 库,因为我们使用了这些库的一些宏函数,这些宏函数可以直接被我们的 C 程序理解。

这是解释好又快的代码源

#include<stdio.h> 
#include<stdarg.h>                      

void Myprintf(char *,...);              //Our printf function
char* convert(unsigned int, int);       //Convert integer number into octal, hex, etc.


int main() 
{ 
    Myprintf(" WWW.FIRMCODES.COM \n %d", 9); 

    return 0;
} 


void Myprintf(char* format,...) 
{ 
    char *traverse; 
    unsigned int i; 
    char *s; 

    //Module 1: Initializing Myprintf's arguments 
    va_list arg; 
    va_start(arg, format); 

    for(traverse = format; *traverse != '\0'; traverse++) 
    { 
        while( *traverse != '%' ) 
        { 
            putchar(*traverse);
            traverse++; 
        } 

        traverse++; 

        //Module 2: Fetching and executing arguments
        switch(*traverse) 
        { 
            case 'c' : i = va_arg(arg,int);     //Fetch char argument
                        putchar(i);
                        break; 

            case 'd' : i = va_arg(arg,int);         //Fetch Decimal/Integer argument
                        if(i<0) 
                        { 
                            i = -i;
                            putchar('-'); 
                        } 
                        puts(convert(i,10));
                        break; 

            case 'o': i = va_arg(arg,unsigned int); //Fetch Octal representation
                        puts(convert(i,8));
                        break; 

            case 's': s = va_arg(arg,char *);       //Fetch string
                        puts(s); 
                        break; 

            case 'x': i = va_arg(arg,unsigned int); //Fetch Hexadecimal representation
                        puts(convert(i,16));
                        break; 
        }   
    } 

    //Module 3: Closing argument list to necessary clean-up
    va_end(arg); 
} 

char *convert(unsigned int num, int base) 
{ 
    static char Representation[]= "0123456789ABCDEF";
    static char buffer[50]; 
    char *ptr; 

    ptr = &buffer[49]; 
    *ptr = '\0'; 

    do 
    { 
        *--ptr = Representation[num%base]; 
        num /= base; 
    }while(num != 0); 

    return(ptr); 
}
于 2015-02-18T10:29:18.550 回答
8

如果你有时间并且真的很好奇,你可以研究一下 GNU libc 的版本:参见printf,它又使用 vprintf,它使用vfprintf

于 2009-11-14T19:17:33.227 回答
3

Linux va_start(3) 手册页提供了编写此类函数的非常好的示例(更简单,但通常所有主要的砖块都在那里)。您也可以检查几乎所有的 libstdc 实现。

于 2009-11-14T20:28:04.643 回答
2

至少有两本书很好地解释了如何printf()编写 -like 格式化函数(以及完整的工作示例):

于 2009-11-15T14:24:40.747 回答
2

这个答案可能会帮助您了解如何编写可变参数函数。请注意,没有进行错误/边界检查,没有设置属性来告诉编译器什么样的参数可能是合适的,与仅使用 printf() 相比没有任何好处。

它可能是也可能不是您正在寻找的示例。

相关的片段(在这里扩展了一点):

#include <stdarg.h>
void _printf(FILE *out, va_list ap)
{
    vfprintf(out, fmt, ap);
}

void printf(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    _printf(stdout, ap);
    va_end(ap);
}

注意:使这些返回正确的类型(有符号整数)留给读者练习。这对我来说很像家庭作业,我只是想让你克服使用 va_start 和 va_end 的任何症结,并表明可以将 va_list 传递给辅助函数以避免在许多几乎相同的实现中重复代码事物。

我强烈建议查看 BSD(甚至 glibc)printf 子系统实现。您还可以查看 uclibc、dietlibc 等。

于 2009-11-15T14:41:16.913 回答
0

它仅适用于“%s”格式说明符。但我认为这仍然有用

void printf(char* str, ...)
{
    char* s;

    va_list vl;
    va_start(vl, str);
    for (char* ptr = str; *ptr != '\0'; ptr++)
    {
        if (*ptr == '%')
        {
            ptr++;
            s = va_arg(vl, char*);
            while (*s != '\0')
                putchar(*s++);
        }
        putchar(*ptr);
    }
    va_end(vl);
}

int main()
{
    char str[60] = "String Array is initialized";
    printf("abcd %s abcd \n", str);
    printf("It work!\n");
}
于 2021-12-12T11:30:59.737 回答