Write your own printf function __ function

Source: Internet
Author: User

We will encounter some functions with variable number of parameters in C language programming, such as printf ()
This function, which is defined as this:
int printf (const char* format, ...);
In addition to having a parameter format fixed, the number and type of subsequent arguments are
Variable, for example we can have the following different invocation methods:

printf ("%d", I); 
printf ("%s", s); 


How do you write the C functions of variable parameters and the function compilers of these variable parameters are actually
Now? This article on the issue of a number of discussions, hoping to help some people. C + +
Users know that these problems do not exist in C + + because of C + + polymorphism. But C + + is a
Superset, the following techniques can also be used in C + + programs. Limited to the level of my own, in the text if there are
Please correct me in the wrong place.

(i) write a simple variable parameter of c function

Let's explore how to write a simple variable-parameter c function. Write variable parameters
The C function uses the following macros in your program:
void Va_start (Va_list arg_ptr, prev_param); 

Type Va_arg (va_list arg_ptr, type); 



VA here is the meaning of the variable-argument (variable parameter).
These macros are defined in Stdarg.h, so programs that use variable parameters should contain this
Header file. Here we write a simple variable-parameter function that has at least one integer
Argument, and the second argument is an integer, which is optional. The function simply prints the values of the two parameters.
void Simple_va_fun (int i, ...) 
{ 
va_list arg_ptr; 
int j=0; 

Va_start (arg_ptr, i); 
J=va_arg (arg_ptr, int); 
Va_end (arg_ptr); 
printf ("%d%d/n", I, j); 
Return 


We can declare our functions in our header file in this way:
extern void Simple_va_fun (int i, ...);
We can call this in the program:
Simple_va_fun (100);
Simple_va_fun (100,200);
As you can see from the implementation of this function, we should have the following steps with variable parameters:
1 first in the function to define a va_list type of variable, here is arg_ptr, this variable
Quantity is a pointer to a parameter.
2) and then using the Va_start macro to initialize the variable arg_ptr, the second parameter of the macro is the first
The previous parameter of a variable parameter is a fixed parameter.
3) then returns the variable parameter with Va_arg and assigns the value to the integer J. Va_arg's second
The parameter is the type of the parameter you want to return, and here is the int type.
4 finally using the Va_end macro to end the acquisition of variable parameters. And then you can make it in the function
With the second argument. If the function has more than one variable parameter, call Va_arg
Take each parameter.
If we use the following three methods to invoke, it is legal, but the result is not the same:
1) simple_va_fun (100);
The result is: 100-123456789 (values that change)
2) Simple_va_fun (100,200);
The result: 100 200
3) Simple_va_fun (100,200,300);
The result: 100 200
We see that the first invocation has errors, the second call is correct, and the third call, although the result
Correct, but there is a conflict with the original design of our function. In the following section, we explore these results
The reason and the variable parameters are handled in the compiler.

(ii) Processing of variable parameters in the compiler

We know that va_start,va_arg,va_end is defined macro in Stdarg.h,
Because of the 1 hardware platform different 2 compiler, so the definition of the macro is also different, under
Face to VC + + in the Stdarg.h x86 platform of the macro definition excerpt as follows ('/' number means line):
typedef char * VA_LIST; 

#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 definition of _intsizeof (n) is primarily for certain systems that require memory alignment. Letter of the C language
The number is pressed from right to left onto the stack, and figure (1) is the position in the stack where the parameters of the function are distributed. I
We see va_list is defined as char*, and some platforms or operating systems are defined as void*.
Look at the definition of va_start, defined as &v+_intsizeof (v), and &v is a fixed parameter on the stack of the
Address, so after we run Va_start (AP, v), the AP points to the first variable parameter in the heap
The address of the stack, as shown in figure:

High Address |-----------------------------|
| function return Address |
|-----------------------------|
|....... |
|-----------------------------|
| nth parameter (first variable parameter) |
|-----------------------------|<--va_start after AP Point
| n-1 parameter (last fixed parameter) |
Low Address |-----------------------------|<--&v
Figure (1)

Then, we use Va_arg () to get the variable parameter value of type T, and the above example is int type, for example, I
Take a look at the return value of the va_arg int type:
J= (* (int*) (AP + _intsizeof (int))-_intsizeof (int));
First ap+=sizeof (int), already points to the address of the next parameter. And then return
int* pointer to ap-sizeof (int), which is exactly the address of the first variable parameter in the stack
(Figure 2). Then use the * to obtain the content of this address (parameter value) to the J.

High Address |-----------------------------|
| function return Address |
|-----------------------------|
|....... |
|-----------------------------|<--va_arg after AP Point
| nth parameter (first variable parameter) |
|-----------------------------|<--va_start after AP Point
| n-1 parameter (last fixed parameter) |
Low Address |-----------------------------|<--&v
Figure (2)

Finally, the meaning of the Va_end macro, x86 platform is defined as ap= (char*) 0, so that the AP is no longer
Point to the stack, but as null. Some are directly defined as ((void*) 0) so that the compiler does not
Generates code for Va_end, such as GCC's x86 platform for Linux.
Here is a question to note: Because the address of the parameter is used for Va_start macros, the
Argument cannot be declared as a register variable or as a function or array type.
About Va_start, Va_arg, Va_end's description is these, we have to pay attention to the
The definitions of different operating systems and hardware platforms are somewhat different, but the principles are similar.

(iii) problems to be noted in programming of variable parameters

Because Va_start, Va_arg, va_end and so on define macro, so it seems very stupid,
The type and number of variable parameters are completely controlled by the program code in the function, and it is not intelligent
To identify the number and type of different parameters.
One might ask: So is the smart identification parameter not implemented in printf? That's because the function
printf analyzes the type of the parameter from the fixed parameter format string, and then calls the Va_arg
To get the variable parameters. That is, you want to implement intelligent recognition of variable parameters is to pass
To make judgments in one's own program.
Another problem is that the compiler does not have a strict prototype check for variable parameter functions
Lattice, bad for programming error. If the Simple_va_fun () is changed to:
void Simple_va_fun (int i, ...) 
{ 
va_list arg_ptr; 
char *s=null; 

Va_start (arg_ptr, i); 
S=va_arg (Arg_ptr, char*); 
Va_end (arg_ptr); 
printf ("%d%s/n", I, s); 
Return 


The variable parameter is the char* type, and when we forget to call the function with two parameters, it appears
Core dump (Unix) or an illegal page error (window platform). But there may not be
Wrong, but the mistake is difficult to discover, does not favor us to write the high quality procedure.
Here's a reference to the compatibility of the VA series macros.
System V UNIX defines va_start as a macro with only one parameter:
Va_start (va_list arg_ptr);
and ANSI C is defined as:
Va_start (va_list arg_ptr, Prev_param);
If we want to use the definition of System V, we should use the definition in the Vararg.h header file
macros, ANSI C macros are incompatible with System V macros, and we generally use ANSI C, so
The definition of ANSI C is sufficient, and it is easy to transplant the program.


Summary:
The function principle of the variable parameter is actually very simple, and the VA series is defined by the macro definition, the real
is related to the stack. When we write a C function of a variable function, there are advantages and disadvantages, so there is no
For the occasion, we do not need to use variable parameters. If in C + +, we should take advantage of C + +
States to realize the function of variable parameters, as far as possible to avoid using the C language method to achieve.

SOURCE case

[Plain] view plaincopyprint?
#include <stdio.h>     
#include <stdlib.h>     
#include <stdarg.h>//is defined as a pointer void _ for a variable argument list     
    
printf (const char * format,...)     
{     
    va_list ap;     
    char ch;     
    Va_start (Ap,format);     
    while (ch=*format++)     
    {     
        switch (CH)     
        {case     
            ' C ':     
            {     
                char ch1= va_arg (Ap,char);     
                Putchar (CH1);     
                break;     
            Case ' s ':     
            {     
                char *p =va_arg (Ap,char *);     
                Fputs (p,stdout);     
                break;     
            Default:     
                putchar (CH);     
}}} int  Main ()     
{     
    _printf ("Hello world!/n", "Jenjien.") ");     
    return 0;     
}   

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.