found that many modern languages have println this function, it is very convenient to use, do not need to add "\ n" Every time you print, you have also achieved a convenient time for debugging.
#include <stdarg.h>
int println(const char *fmt, ...)
{
char printf_buf[1024];
va_list args;
int printed;
va_start(args, fmt);
printed = vsprintf(printf_buf, fmt, args);
va_end(args);
puts(printf_buf);
return printed;
}
The variable parameter function of C language is used here, so we can talk about the variable parameter function of C language. The parameter of the so-called variable parameter function is a function that can be an indefinite number. Above we have seen the definition of the variable parameter function, using the shape int println(const char *fmt, ...)
to define the variable parameter function.
Note: The first parameter in the previous example fmt
is not omitted, and the variable parameter function requires at least one normal formal parameter.
One important reason why C language supports variable parameter functions is that when a C function call is specified in the C call specification, the order of the arguments into the stack is from right to left, which means that the parameter at the top of the stack is the first parameter. In this way, the called function does not need to be concerned that the caller will pass several parameters in, as long as the care of themselves with a few parameters can be.
For example, such a call
println("%d %d", 10, 20, 30, 40);
println("hello world");
The corresponding assembly code is:
push 28h
push 1Eh
push 14h
push 0Ah
push offset string "%d %d" (0D4574Ch)
call println (0D410B9h)
add esp,14h
As you can see, the right println("%d %d", 10, 20, 30, 40);
call really pushes the argument from right to left into the stack.
There is another problem here: Because of the variable parameter function, when the function definition does not define the formal parameter prototype, the call when the use of parameters? To do this, the C language defines the following macros:
void va_start(va_list ap, last);//取第一个可变参数(如上述printf中的i)的指针给ap,last是函数声明中的最后一个固定参数(比如printf函数原型中的*fromat);
type va_arg(va_list ap, type);//返回当前ap指向的可变参数的值,然后ap指向下一个可变参数;type表示当前可变参数的类型(支持的类型位int和double);
void va_end(va_list ap);//将ap置为NULL
It is defined in the header file as follows:
/*
* define a macro to compute the size of a type, variable or expression,
* rounded up to the nearest multiple of sizeof(int). This number is its
* size as function argument (Intel architecture). Note that the macro
* depends on sizeof(int) being a power of 2!
*/
#define_intsizeof(N) ( (sizeof(N) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define _VA_LIST char*
typedef _VA_LIST va_list;
#define va_dcl va_list va_alist;
-
#define ( ap ap = ( va_list ) & va_alist
-
#define ( ap T ) ( Span class= "pun" >* ( t *) (( ap Span class= "pun" >+= _intsizeof ( t - _intsizeof ( t )
#define va_end(ap) ap = (va_list)0
From the definition above it is easy to see that you are pointing to the va_start
ap
First optional parameter. va_arg
returns the current parameter in the argument list and makes ap
a point to the next parameter in the argument list. va_end
will be ap
placed as a null pointer.
About _INTSIZEOF
doing a simple explanation: because sizeof (int) is 2^n
, so its bit pattern must be 1...000
, it minus one, it becomes 11..11
such a bit pattern, so plus sizeof(int) - 1
, if carry, is definitely sizeof(int)
the integer times, if not carry, is already an sizeof(int)
integer multiple, so the macro takes sizeof(n)
an integer multiple of n upwards.
From for notes (Wiz)
C language println function