当前位置:网站首页>Implement printf function by yourself

Implement printf function by yourself

2020-11-09 15:25:24 shzwork

origin:https://www.e-learn.cn/content/qita/716071

First of all, let's take a look at the basics .

printf The format characters are as follows ,

Format characters

explain

d

Output integers in signed decimal form ( Integers do not output symbols )

u

Output integers in unsigned decimal form

x

Output an integer in hexadecimal unsigned form ( Don't output preamble 0x),

use x Then output hexadecimal number of a~f In lower case

c

Output in character form , Only one character is output

s

Output string

stay C In language , Not only is the type of the parameter variable , And the number of parameters is also variable . in other words , In the formal parameter list, you can not explicitly specify the number and type of parameters to be passed , As mentioned above printf That's what functions do . This function is called a variable parameter function . The number and type of parameters of variable length parameter function are variable , But its design principle is consistent with that of fixed parameter function , We have a way to tell the variable parameter function the number and type of parameters that are not specified .

printf The statement of :

int printf(const char *format, ...);

format: Fixed parameter

... : Variable parameters ( Variable parameter )

 

stay C In language , The declaration of the variable parameter function is placed in atdarg.h In the standard library , Of course, you can include it directly and use it , But we define it here ( Refer to the macro definition of the header file ).

typedef char * va_list;
/*  When sizeof(n)=1/2/4 when ,_INTSIZEOF(n)=4 */
#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_arg(ap,t) (ap = ap + _INTSIZEOF(t), *(t *)(ap - _INTSIZEOF(t)))
/*  The meaning of the following words is , First point to the address of the next variable , And then again ( reduce ) Come back , Finally, take the value in its original address  */ 
#define va_arg(ap,t) (*(t *)(ap = ap + _INTSIZEOF(t), ap - _INTSIZEOF(t)))
/* When the pointer runs out, it points to 0 Address , Prevent the appearance of wild pointer */
#define va_end(ap) ( ap = (va_list)0 )

There's a little bit of caution here #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) -1) & ~(sizeof(int) - 1) ), It may not be easy to understand , Here is a knowledge point : Because in x86(32 Bit machine ) Under the platform ,GCC By default, the compiler presses 4 Byte alignment , So when sizeof(n)=1/2/4 when ,_INTSIZEOF(n)=4 When the variable type is char,unsigned int,int, That's not enough 4 All bytes are in accordance with 4 Byte completion .

Here's how My_printf.c

#include  "my_printf.h"


//==================================================================================================
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_arg(ap,t)    ( *(t *)( ap=ap + _INTSIZEOF(t), ap- _INTSIZEOF(t)) )
#define va_end(ap)      ( ap = (va_list)0 )                                      // There is no explanation here , It's not difficult to understand. 

//==================================================================================================
unsigned char hex_tab[]={'0','1','2','3','4','5','6','7',\
		                 '8','9','a','b','c','d','e','f'};               // Output characters in various bases 

static int outc(int c) 
{
	__out_putchar(c);                                        // there _out_putchar In fact, that is putchar, stay .h In the definition of 
	return 0;
}

static int outs (const char *s)                                 // Output string 
{
	while (*s != '\0')	
		__out_putchar(*s++);
	return 0;
}

static int out_num(long n, int base,char lead,int maxwidth)            
{
	unsigned long m=0;
	char buf[MAX_NUMBER_BYTES], *s = buf + sizeof(buf);    // sizeof It's the ending '\0' ,strlen not 
	int count=0,i=0;				// Note that there s Point to buf The end of , As for why to keep looking down 	
			

	*--s = '\0';                               // First --, At the end of assignment , because sizeof Count the length inside the terminator 
	
	if (n < 0){
		m = -n;                        // If the output is a negative number, it is negated 
	}
	else{
		m = n;
	}
	
	do{
		*--s = hex_tab[m%base];
		count++;
	}while ((m /= base) != 0);       // The number to be printed is stored in the array from bits to bits buf in , If it doesn't point to buf end ,
	  if (n < 0)
		*--s = '-';    // If it's negative, add a minus sign 
	
	return outs(s);
}
   

/*reference :   int vprintf(const char *format, va_list ap); */
static int my_vprintf(const char *fmt, va_list ap) 
{
	char lead=' ';
	int  maxwidth=0;
	
	 for(; *fmt != '\0'; fmt++)
	 {
			if (*fmt != '%') {             // Order search judgment , encounter % On the launch , Otherwise, continue to loop out the output 
				outc(*fmt);            
				continue;       		
			}

		    fmt++;
		if(*fmt == '0'){                   // encounter ‘0’ Explain that the preamble is 0
			lead = '0';
			fmt++;	
		}

		
		
		while(*fmt >= '0' && *fmt <= '9'){		 // The next number is the length , Calculate the specified length 
			maxwidth *=10;
			maxwidth += (*fmt - '0');
			fmt++;
		}
		
			switch (*fmt) {                                  // Determine the format output 
		case 'd': out_num(va_arg(ap, int),          10,lead,maxwidth); break;
		case 'o': out_num(va_arg(ap, unsigned int),  8,lead,maxwidth); break;				
		case 'u': out_num(va_arg(ap, unsigned int), 10,lead,maxwidth); break;
		case 'x': out_num(va_arg(ap, unsigned int), 16,lead,maxwidth); break;
			case 'c': outc(va_arg(ap, int   )); break;		
			case 's': outs(va_arg(ap, char *)); break;		  		
				
			default:  
				outc(*fmt);
				break;
			}
	}
	return 0;
}


//reference :  int printf(const char *format, ...); 
int printf(const char *fmt, ...) 
{
	va_list ap;

	va_start(ap, fmt);
	my_vprintf(fmt, ap);	
	va_end(ap);
	return 0;
}


int my_printf_test(void)
{
	printf("My_printf test\n\r") ;	
	printf("test char           =%c,%c\n\r", 'A','a') ;	
	printf("test decimal number =%d\n\r",    123456) ;
	printf("test decimal number =%d\n\r",    -123456) ;	
	printf("test hex     number =0x%x\n\r",  0x55aa55aa) ;	
	printf("test string         =%s\n\r",    "yoyoyo") ;	
	printf("num=%08d\n\r",   12345);
	printf("num=%8d\n\r",    12345);
	printf("num=0x%08x\n\r", 0x12345);
	printf("num=0x%8x\n\r",  0x12345);
	printf("num=0x%02x\n\r", 0x1);
	printf("num=0x%2x\n\r",  0x1);

	printf("num=%05d\n\r", 0x1);
	printf("num=%5d\n\r",  0x1);

	return 0;
}


 

The experimental results are as follows :

版权声明
本文为[shzwork]所创,转载请带上原文链接,感谢