/ **** ** Copyright (C) 1985-1997, Microsoft Corporation. All Rights Reserved. ** Purpose: * Defines Printf () - Print Formatted Data ******** *********************************************************** ******************** / #include
#include
#include
#include
#include
#include
#include
/ **** int printf (format, ...) - print formatted data ** Purpose: * Prints formatted data on stdout using the format string to * format data and getting as many arguments as called for * Uses temporary buffering to improve efficiency * _output does the real work here ** Entry:. * char * format - format string to control data format / number of arguments * followed by list of arguments, number and type controlled by * format string ** Exit: * returns number Of characterprinted ** exception: ************************************************************ *********************************************** / INT __CDECL Printf (Const Char * Format, ... ) / ** stdout '' print ',' '' '' ''ormatted * / {va_list arglist; int buffing; int RetVal; va_start (arglist, format); _ asserte! = null); // assertion macro. If the output format string pointer is empty, it is asserted in the Debug version, and the report is an error. _lock_str2 (1, stdout); buffing = _stbuf (stdout); // stdout: Specify output to screen retval = _output (stdout, format, arglist); _ ftbuf (buffing, stdout); _ unlock_str2 (1, stdout); return (RetVal) );} The source code 1 for PrINTF () is obtained from the optional parameter in the optional parameter function, and the operations these parameters typef char * va_list; void va_start (va_list arg_ptr, prev_param); type va_arg (VA_List Arg_ptr, Type ); VOID VA_END (VA_LIST ARG_PTR); hypothesis function contains a must-selection parameter and multiple optional parameters, and the necessary parameters are declared as a normal data type, and the value of the variable can be obtained by parameter name. Optional parameters are operated by macro VA_START, VA_ARG, and VA_END (defined in stdarg.h or var or varargs.h), that is, the current parameters are returned by setting the first optional parameter pointer, and the pointer is reset after returning the parameters. Operate all optional parameters. VA_START: Provides a convenient means for the parameters of the function of obtaining a variable number parameter. Set arg_ptr to point to a pointer to the first optional parameter in the transfer function parameter list, and this parameter must be a VA_List type. Prev_Param is a must-select parameter before the first optional parameter in the parameter list. VA_ARG: Returns the value of the parameters pointed to by arg_ptr, and the address is added to the next parameter. TYPE is the type of the current parameter, used to calculate the length of the parameter, determine the starting position of the next parameter. It can be applied multiple times in a function until all parameters of the function are obtained, but must be called behind the macro VA_Start. VA_END: After obtaining all the parameters, set the pointer Arg_Ptr to NULL. The following example shows: # include # include
Int average (int first, ...); void main (void) {/ * call with 3 integers (-1 is used as terminator). * / printf ("Average IS:% D / N", Average (2, 3, 4, -1)); / * Call with 4 integers. * / Printf ("Average IS:% D / N", Average (5, 7, 9, 11, -1)); / * Call with just -1 Terminator. * / Printf ("Average IS:% D / N", Average (-1));} int average (int first, ...) {Int count = 0, SUM = 0, i = first; VA_LIST MARKER; VA_START (Marker, First); / * Initialize Variable Arguments. * / while (i! = -1) {SUM = I; Count ; I = VA_ARG (Marker, Int);} VA_END (MARKER); / * RESET VARIABLE Arguments. * / RETURN (SUM? (Sum / count): 0);} Return value is: Average IS: 3AVERAGE IS: 8AVERAGE IS: 0 In summary, in the printf () function, only export A string can also output a string information containing multiple optional parameters in a certain form. Therefore, you must first pass these macros to get all optional parameters. In the above source code, it can be seen that in Printf (), only the macro AT_START is used, and the first address of the optional parameter is assigned to Arglist. 2, lock string and output string to screen #define _lock_str2 (i, s) _lock_file2 (i, s) void __cdecl _lock_file2 (int, void *); # define _unlock_str2 (i, s) _Unlock_file2 (i, s) void __cdecl _unlock_file2 (int, void *); int __cdecl _stbuf (file *); void __cdecl _ftbuf (int, file *); int __cdecl _output (file *, const char *, va_list); in the Output function, read format characters Each character in the string then processes it, the processing mode is performed according to the meaning representing each character, such as: normal characters Directly utilize functions write_char (ch, & charSout); output to the console. The main part of these is the processing of the conversion setup (D, C, S, f), and now, the partial code will now be described in detail, and only the most basic conversion specifeters are explained, and these basic conversion specifiers are explained. The modified modifier is performed separately. Below is the function output () (output.c) section source code: CASE ST_TYPE: / / Indicates the type of characters currently processed into a conversion specifier. ... Switch (CH) {// The following to the acquisition of the parameters is made using macro VA_ARG (VA_LIST ARG_PTR, TYPE);
Case '' C '': {// Get a single character from the parameter table, output into the buffer string, at this time, TYPE = int buffer [0] = (char) get_int_ARG (& argptr); / * get char to print * / text = buffer; Textlen = 1; / * Print Just A Single Character * /} Break; Case '' S '': {// Get strings from the parameter table, output into the buffer string, at this time, TYPE = char * INT i; char * p; / * temps * / text = get_ptr_arg (& argptr); ...} Break; Case '' w '': {// Pass wide character for processing ...} / * Case '' W '' * / Break; ... case '' ': Case' 'f' ': Case' 'g' ': {// Operate the floating point number ... # if! longdouble_is_double / * do the conversion * / if (flags & fl_longdouble) {_clDouble *) argptr, text, ch, precision, capexp); VA_ARG (Argptr, longdouble); // Treated long double precision type, at this time, TYPE = long double} else # Endif / *! longdouble_is_double * / {// Treated the double-precision type, at this time, TYPE = Double_CFLTCVT ((Double *) argptr, Text, Ch, Precision, CAPEXP); VA_ARG (Argptr, Double);} ... Break; // Treat Case '' D '': Case '' 'I' ': ... Goto Common_INT; Case' U '': RADIX = 10; goto common_int; Case '' P '': ... goto compon_int; case '' o '': ... Note: For floating-point Double and Long Double, there is a corresponding conversion specifier (% F represents double precision type,% LF Indicates a long bid-podium), but Float is not. The reason is that under K & RC, the FLOAT value is used to express into a Double type before expressing or used as a parameter. ANSI C generally does not automatically convert Float into Double. Some programs have assumed that the float parameters are converted into Double, in order to protect a large number of such programs, all the FLOAT parameters of all Printf () functions are automatically converted into Double type. Therefore, in K & RC or ANSI C, there is no need to display the Float type with a specific conversion set. In summary, the conversion specifier must be with the type of characters to be printed. Typically, the user has a choice. For example, if you want to print a value of an int type. You can only use% D,% X or% O. All of these specifiers indicate a value to print an int type; they simply provide several different representations of a value. Similarly, you can use% F,% g and% e to represent the value of the Double type. But if the conversion instructions are not matched, the unexpected results will occur.