C language variable parameter function details the example

  • 2020-04-02 01:54:31
  • OfStack

Look at the code


printf( " hello,world! " ); The number of parameters is 1 A. 
printf( " a=%d,b=% s. ,c=%c " ,a,b,c); The number of parameters is 4 A. 

How do you write variable-parameter functions? Let's first look at how the printf function prototype is defined.
Under Linux, type man 3 printf, and you can see the prinf function prototype as follows:

SYNOPSIS
#include <stdio.h>
int printf(const char *format, ...);

The next three points... Indicates that the number of printf arguments is variable.
How to implement variable-parameter functions?
2. Write variable function preparation
In order to write variable-argument functions, we usually use them < Stdarg. H > The following functions are defined in the header file:

void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);

Among them:
Va_list is a data structure that holds a list of parameters.
The va_start function initializes the parameter list based on last.
The va_arg function is used to take an argument from the parameter list, the type of which is specified by type.
The va_copy function is used to copy the parameter list.
The va_end function does the work of cleaning up the parameter list.
The above functions are usually implemented with macros, such as in standard ANSI form, which are defined as:

typedef char * va_list; //String pointer
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )

The macro _INTSIZEOF is used to align Pointers in integer bytes, because under the c call protocol, the parameter push is all integer bytes (Pointers or values).
Function official description, if you see English is annoying, you can ignore the following instructions.
Va_start ()
            The   Va_start () macro initializes the ap for subsequent use by va_arg and ()
            Va_end (), and must be called first.
            The argument last is The name of The last argument before The   variable
            Argument list, that is, the last argument of which the calling function
            Knows the type.
            Because the address of this argument may   be   Informs the   The in   the   Va_start ()
            Macro,   It should not be declared as a register variable, or as a func
            Tion or an array type.
Va_arg ()
            The va_arg () macro expands to The an expression that has The type and value
            of   the   next   The argument in the call.   The argument ap is The va_list ap
            An initialized by va_start ().   Each call to va_arg() modifies ap   so   that
            the   next   Call returns the next argument.   The argument type is a type
            Name specified so that the type of a pointer to an object that has   the
            Information type can be obtained simply by adding a * to type.
            The   First use of the va_arg() macro after that of the va_start() macro
            Returns the argument after last.     Successive   invocations   The return   the
            Values of the remaining arguments.
            The If   S a   is   no   Next argument, or if type is not compatible with the
            Type of the actual next argument (as promoted according to the)   The default
            Argument arguments), random errors will occur.
            The If   Ap is passed to a function that USES va_arg(ap,type) then the value
            Of ap is undefined after the return of that function.
Va_end ()
            Each invocation of va_start() must be matched by a correspondence   Invo �
            Cation of va_end() in the same function.   After the call va_end(ap) the
            Variable ap is undefined.   Multiple traversals of the list, each brack
            eted   By va_start() and va_end() are possible.   Va_end () may be a macro
            Or a function.
An example from GNU:

#include <stdio.h>
#include <stdarg.h>
void
foo(char *fmt, ...)
{
  va_list ap;
  int d;
  char c, *s;
 va_start(ap, fmt);
 while (*fmt)
     switch (*fmt++) {
     case 's': 
     s = va_arg(ap, char *);
         printf("string %sn", s);
         break;
     case 'd': 
         d = va_arg(ap, int);
         printf("int %dn", d);
         break;
     case 'c': 

        c = (char) va_arg(ap, int);
        printf("char %cn", c);
        break;
   }
   va_end(ap);
}

Description:
Va_start (ap, FMT); Used to initialize a list of variable parameters based on FMT.
Va_arg (ap, char *); Used to take an argument from the argument list, where the char * is used to specify that the argument is of type string. After each call to va_arg, the argument list ap is changed to get the next argument on the next call.
Va_end (ap); Used to do some cleanup on the parameter list. After the va_end call, the ap is no longer valid.
The above program gave us an idea to implement printf function, that is: by calling va_start function, to get a list of parameters, and then we can take out the parameters to output.
Example 3.
For example, for printf(" a=%d,b=%s,c=%c ",a,b,c) statement; The value of FMT is a=%d,b=%s, and c=%c. The va_start function is called to store the parameters a,b, and c in ap. Note: % in FMT is a special character, and the parameter followed by % indicates the parameter type.
Therefore, our simple printf function is as follows:

#include <stdio.h>
#include <stdarg.h>
void
myprintf(char *fmt, ...)
{
  va_list ap;
  int d;
  double f;
  char c; 
  char *s;
  char flag;
  va_start(ap,fmt);
  while (*fmt){
   flag=*fmt++;
   if(flag!='%'){
 putchar(flag);
 continue;
  }
  flag=*fmt++;//Remember to move back one
    switch (flag) 
  { 
   case 's':
 s=va_arg(ap,char*);
 printf("%s",s);
 break;
   case 'd':          
 d = va_arg(ap, int);         
 printf("%d", d);         
 break;     
   case 'f':          
 d = va_arg(ap,double);         
 printf("%d", d);         
 break;
   case 'c':    
 c = (char)va_arg(ap,int);        
 printf("%c", c);        
 break;
   default:
 putchar(flag);
 break;
  }   
  }
  va_end(ap);
}
int main(){
  char str[10]="linuxcode";
  int i=1024;
  double f=3.1415926;
  char c='V';
  myprintf("string is:%s,int is:%d,double is:%f,char is :%c",str,i,f,c);
}

From the above we can know the variable parameter function writing, must pass in a parameter FMT, to tell our function how to determine the number of parameters. Our variable-argument function determines the number of arguments by parsing the argument itself.
For example, we write a summation function, whose function implementation is as follows:

int sum(int cnt,...){
    int sum=0;
int i;
    va_list ap;
    va_start(ap,cnt);
for(i=0;i<cnt;++i)
 sum+=va_arg(ap,int);
    va_end(ap);
return sum;
}

To summarize, initialize the list of parameters by va_start (so you can get the exact number of parameters), then use the va_arg function to extract the parameters you want from the list, and finally call va_end to perform the cleanup.


Related articles: