Linux Cプログラミング連載(7)-変数パラメータ実装printf


【コードリスト】
#include <stdio.h>

#define va_list void*
#define va_end(arg)
#define va_start(arg, start) arg = (va_list)(((char *)&(start)) + sizeof(start))
#define va_arg(arg, type) *(type*)arg; arg = (char *)arg +sizeof(type)

char *itoa(int num, char *str, int radix)
{
	char string[] = "0123456789abcdefghijklmnopqrstuvwxyz";
	char *ptr = str;
	int i,j;
	
	while(num)
	{
		*ptr++ = string[ num%radix ];
		num /= radix;

		if(num < radix)
		{	
			*ptr++ = string[num];
			*ptr = '\0';
			break;
		}
	}

	j = ptr - str -1;

	for(i=0; i<(ptr-str)/2; i++)
	{
		int temp = str[i];
		str[i] = str[j];
		str[j--] = temp;
	}

	return str;
}

int mprintf(const char *format, ...)
{
	va_list arg;
	int done = 0;

	va_start(arg, format);

	while(*format != '\0')
	{
		if(*format == '%')
		{
			if(*(format+1) == 'c')
			{
				char c = (char)va_arg(arg,int);
				putc(c,stdout);
			} else if(*(format+1) == 'd'||*(format+1) == 'i')
			{
				char store[20];
				int i = va_arg(arg,int);
				char *str = store;
				itoa(i,store,10);
				while(*str != '\0') putc(*str++,stdout);
			} else if(*(format+1) == 'o')
			{
				char store[20];
				int i = va_arg(arg,int);
				char *str = store;
				itoa(i,store,8);
				while(*str != '\0') putc(*str++,stdout);
			} else if(*(format+1) == 'x')
			{
				char store[20];
				int i = va_arg(arg,int);
				char *str = store;
				itoa(i,store,16);
				while(*str != '\0') putc(*str++,stdout);
			} else if( *(format+1) == 's' )

			{

				char* str = va_arg(arg, char*);

				while( *str != '\0') putc(*str++, stdout);

			}

			format += 2;
				
		} else {

				putc(*format++, stdout);
			}
	}

    va_end (arg);



    return done;
}

int main(int argc, char* argv[])

{ 

    int n = 255;

    char str[] = "hello, world!";





    // Test vprintf function

    mprintf("n = %d
", n); mprintf("n = %i
", n); mprintf("n = %o
", n); mprintf("n = %x
", n); mprintf("first char = %c
", str[0]); mprintf("str = %s
", str); mprintf("%s\tn = %d
", str, n); return 0; }

【解析】
(1)
#define va_start(arg, start) arg = (va_list)(((char *)&(start)) + sizeof(start))

argをstart(すなわちformat)の後のアドレスに向けると,パラメータのヘッダアドレスを変えることができる.
(2)
#define va_arg(arg, type) *(type*)arg; arg = (char *)arg +sizeof(type)

va_が定義されていますarg関数、argとtypeの2つのパラメータがあります.argがtype*タイプのポインタであることを示した.この関数の役割は、ポインタを次の可変パラメータに向けることです.
【リンク】関数定義の2つの形式
(1) int func(int a, int b);
(2) int func(a,b) int a, int b;
 
転載は出典を明記してください.学習交流だけで、商業目的に使用しないでください.
Copyright @ http://blog.csdn.net/tandesir