Saturday, August 30, 2014

variable length arugment list in c

keypoints

  • initialization of variable 
    • (va_list  <variable>)
  • like malloc or memset  
    • va_start(<variable>,<number>) 
  • like foreach  
    • va_arg(<variable>,<datatype>) inside loop
  • like memory free 
    • va_end(<variable>)

#include <stdio.h> #include <stdarg.h> double average(int num,...) { va_list valist; double sum = 0.0; int i; /* initialize valist for num number of arguments */ va_start(valist, num); /* access all the arguments assigned to valist */ for (i = 0; i < num; i++) { sum += va_arg(valist, int); } /* clean memory reserved for valist */ va_end(valist); return sum/num; } int main() { printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5)); printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15)); }

very best explanation for each call present here:

The standard header <stdarg.h> contains a set of macro definitions that define how to step through an argument list. The implementation of this header will vary from machine to machine, but the interface it presents is uniform.
  1. The type va_list is used to declare a variable that will refer to each argument in turn; in minimal_printf , this variable is called ap , for "argument pointer".
  2. The macro va_start initializes ap to point to the first unnamed argument. It must be called once before ap is used.
  3. There must be at least one named argument; the final named argument is used by va_start to get started.
  4. Each call of va_arg returns one argument and steps ap to the next; va_arg uses a type name to determine what type to return and how big a step to take.
  5. Finally, va_end does whatever cleanup is necessary. It must be called before the program returns.
Here is the implemetation of our minimal_printf() which gives us idea about both the original printf() and variable number of argument function.

https://www.hackerearth.com/practice/notes/know-our-printf-variable-number-of-arguments-to-a-function/

Easy printf implementaion:

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

void errmsg( const char* format, ... )
{
  va_list arglist;

  printf( "Error: " );
  va_start( arglist, format );
  vprintf( format, arglist );
  va_end( arglist );
}

int main( void )
{
  errmsg( "%s %d %s", "Failed", 100, "times" );
  return EXIT_SUCCESS;
}
Ref: https://stackoverflow.com/questions/5977326/call-printf-using-va-list

or

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

char ErrStr[128];
char Status[128];
int flag=1;

void Feeder( char *buff,...)
{
    va_list arglist;

    va_start(arglist,buff);

    //customized operations...
    if (flag<0)
        vsprintf(ErrStr,buff,arglist);
    else if (flag>=0)
        vsprintf(Status,buff,arglist);

    va_end(arglist);
}

int main()
{
    Feeder("Hello World %d %f %s\n",5,5.55,"55.55");
    if(Status[0])
        printf("Result: %s\n",Status);

    return 0;
}
Ref: http://cc.byexamples.com/2007/01/18/va-list-create-function-like-printf-2/

Full printf implementation:

 #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); 
}
#include <stdio.h>
#include <stdarg.h>

extern char *itoa(int, char *, int);

void myprintf(const char *fmt, ...)
{
const char *p;
va_list argp;
int i;
char *s;
char fmtbuf[256];

va_start(argp, fmt);

for(p = fmt; *p != '\0'; p++)
 {
 if(*p != '%')
  {
  putchar(*p);
  continue;
  }

 switch(*++p)
  {
  case 'c':
   i = va_arg(argp, int);
   putchar(i);
   break;

  case 'd':
   i = va_arg(argp, int);
   s = itoa(i, fmtbuf, 10);
   fputs(s, stdout);
   break;

  case 's':
   s = va_arg(argp, char *);
   fputs(s, stdout);
   break;

  case 'x':
   i = va_arg(argp, int);
   s = itoa(i, fmtbuf, 16);
   fputs(s, stdout);
   break;

  case '%':
   putchar('%');
   break;
  }
 }

va_end(argp);
}



REf:
http://www.firmcodes.com/write-printf-function-c/
https://www.eskimo.com/~scs/cclass/int/sx11b.html

Used area:
  • To calculate average
  • in cli framework
Reference:

No comments:

Post a Comment