Rajesh M
Rajesh M

Reputation: 189

How to write my own printf() in C?

Actually I am trying to write my own printf() in C by using varags. But I am not getting the correct solution for this. Can anyone help me out?

Upvotes: 18

Views: 71249

Answers (8)

Snehasish Konger
Snehasish Konger

Reputation: 21

    #include <stdarg.h>

int my_printf(const char *format, ...)
{
    va_list args;
    va_start(args, format);

    int i = 0;
    while (format[i])
    {
        if (format[i] == '%')
        {
            i++;
            switch (format[i])
            {
                case 'd':
                {
                    int x = va_arg(args, int);
                    printf("%d", x);
                    break;
                }
                case 'f':
                {
                    double x = va_arg(args, double);
                    printf("%f", x);
                    break;
                }
                case 'c':
                {
                    int x = va_arg(args, int);
                    printf("%c", x);
                    break;
                }
                case 's':
                {
                    char *x = va_arg(args, char*);
                    printf("%s", x);
                    break;
                }
                case 'x':
                case 'X':
                {
                    int x = va_arg(args, int);
                    printf("%x", x);
                    break;
                }
                case 'p':
                {
                    void *x = va_arg(args, void*);
                    printf("%p", x);
                    break;
                }
                case '%':
                    putchar('%');
                    break;
                default:
                    putchar(format[i]);
                    break;
            }
        }
        else
        {
            putchar(format[i]);
        }
        i++;
    }

    va_end(args);
    return 0;
}
int main()
{
    int x = 5;
    double y = 3.14;
    char c = 'a';
    char *str = "Hello World!";
    my_printf("The value of x is %d, y is %f, c is %c, str is %s", x, y, c, str);
    return 0;
}

I think creating a new function without using the printf(), that would do everything of the printf() function is quite tough. So, I tried in this way. Here I've added a documentation for the code- Printf() function

Upvotes: 0

manu
manu

Reputation: 51

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

// You can write your own low level function to write to display or hardware
void local_put(char c){
    putchar(c);
}

void decimal_to_baseN(char *converted, unsigned int num, int base) 
{
    if (num == 0) {
        converted[0] = '0';
        converted[1] = '\0';
        return;
    }
    int MAX_REP_LEN = 250;
    char NUM_BASE[] = "0123456789ABCDEF";
    char buffer[MAX_REP_LEN];

    int i = MAX_REP_LEN - 1;
    while (num != 0) {
        buffer[i--] = NUM_BASE[num % base];
        num /= base;
    }
    int counter = 0;
    for (int j = i + 1; j <= MAX_REP_LEN - 1; j++) {
        converted[counter++] = buffer[j];
    }
    converted[counter] = '\0';
}


void my_print(char *c, ...)
{
    int num;
    va_list arg;
    va_start(arg, c);
    char outbuf[2048];
    int i;
    char *ch;
    double db_val;
    unsigned int uint_val;
    while(*c!='\0'){
        if(*c=='%'){
            c++; // To incement to the formating character
            // processing the formatting character
            switch(*c){
                case 'b':
                case 'B':
                case 'h':
                case 'H':
                case 'O':
                case 'o':
                case 'd':
                case 'D':
                case 'i':
                case 'I':
                    num = va_arg(arg, int);
                    if(num<0){
                        // Simple - sign is used instead of 2s complement
                        local_put('-');
                        num = num * -1;
                    }
                    if(*c=='b' || *c=='B'){
                        decimal_to_baseN(outbuf, num, 2);
                    }else if(*c=='o' || *c=='O'){
                        decimal_to_baseN(outbuf, num, 8);
                    }else if(*c=='d' || *c=='D'){
                        decimal_to_baseN(outbuf, num, 10);
                    }else if(*c=='h' || *c=='H'){
                        decimal_to_baseN(outbuf, num, 16);
                    }
                    
                    for(int i=0;outbuf[i]!='\0';i++){
                        local_put(outbuf[i]);
                    }
                break;
                
                case 'c':
                case 'C':
                    num = va_arg(arg, int);
                    local_put(num);
                break;
                    
                case 's':
                case 'S':
                    ch = va_arg(arg, char*);
                    while(*ch!='\0'){
                        local_put(*ch++);
                    }
                break;
                
                case 'f':
                case 'F':
                    db_val = va_arg(arg, double);
                    sprintf(outbuf, "%f", db_val);
                    for(int i=0;outbuf[i]!='\0';i++){
                        local_put(outbuf[i]);
                    }
                break;
                
                case 'u':
                case 'U':
                    uint_val = va_arg(arg, unsigned int);
                    sprintf(outbuf, "%u", uint_val);
                    for(int i=0;outbuf[i]!='\0';i++){
                        local_put(outbuf[i]);
                    }
                break;
            }
        }else{
            local_put(*c);   
        }
        c++;
    }
    va_end(arg);
}

int main()
{
    int num = 100;
    my_print("The Decimal: %d\r\n", num);
    my_print("The Unsigned int: %u\r\n", 4294967295);
    my_print("The Binary: %b\r\n", num);
    my_print("The Octel: %o\r\n", num);
    my_print("The Hex: %h\r\n", 999);
    my_print("The Character: %c\r\n", 'C');
    my_print("The String: %s\r\n", "Annie");
    my_print("The Float: %f\r\n", 4.35);
    return 0;
}

Upvotes: 0

Jin
Jin

Reputation: 1

It only work for '%s' format specifier. But I think this is still useful

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");
}

Upvotes: 0

vishal
vishal

Reputation: 261

Before implementation of printf( ) function we have to deal with unusual problem which is variable arguments. As we know that printf can take many arguments besides string. So we have to use a standard library called stdarg.h to handle this variable argument problem. In this implementation context, we don’t need learn whole stdarg.h library because we use some macro functions of these library which is understandable directly by our C program.

Here is the code source which explain nice and fast

#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); 
}

Upvotes: 25

user50049
user50049

Reputation:

This answer may help you to understand how to write variadic functions. Note, no error / bounds checking is done, no attributes are set to tell the compiler what kind of arguments might be suitable, no benefit over just using printf() is achieved.

It may or may not be the example you are looking for.

The relevant snippet (expanded a bit here):

#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);
}

Note: making these return the correct type (signed integer) is left as an exercise for the reader. This looks a lot like homework to me, I'm just trying to get you past any sticking point of using va_start and va_end, plus showing that a va_list can be passed to helper functions to avoid duplicating code in so many implementations of almost the same thing.

I strongly advise looking at the BSD (or even glibc) printf sub system implementation. You could also look at uclibc, dietlibc, etc ..

Upvotes: 3

Jonathan Leffler
Jonathan Leffler

Reputation: 753725

There are at least two books with good explanations of how a printf()-like formatting function can be written (and complete working examples):

Upvotes: 2

Roman Nikitchenko
Roman Nikitchenko

Reputation: 13046

Linux va_start(3) man page gives very good example of writing such functions (much more simpler but in general all the major bricks are there). Also you could examine almost any libstdc implementation.

Upvotes: 3

Steffen
Steffen

Reputation: 2948

If you have some time and are really curious you could study the GNU libc's version: See printf, which in turn uses vprintf, which uses vfprintf

Upvotes: 10

Related Questions