본문 바로가기
programming/구현

printf 구현하기

by Ryuuu 2018. 1. 28.

구현 환경 : ubuntu 16.04 LTS , 64비트, gcc 컴파일


헤더는 가변인자를 받아야 하므로 stdarg만 쓴다. (가변인자 함수를 구현하기는 너무 힘들다...)


구현 기능 : 형식지정자 %d , %s, %c, %i, %u, %x 

   형식지정자 사이 숫자 ex) %10d, %20s ...


* %X %C 대문자로 출력 기능 추가


먼저 헤더 파일을 사용하지 않음으로 출력해주는 함수를 어셈으로 직접 만들어 준다.


 
section .data

section .text

global write_main
write_main:

        push rbp
        mov rbp, rsp
        push rdi
        lea rsi, [rsp]
        mov rax, 1
        mov rdi, 1
        mov rdx, 1
        syscall
        leave
        ret

64비트는 rdi가 함수의 첫번째 인자로 들어가기 때문에 rdi를 push해주고 write systemcall을 해주었다.


nasm -f elf64 printf.nasm
gcc -o printf printf.o printf.c

어셈으로 만들어주는 것은 nasm을 사용하여 목적파일(.o)로 만들고 함께 컴파일 해준다.


그 다음부턴 c로 구현해 주면 된다.


 
#include

void r_c(char str, int rank, char alpha);
void r_s(char *str,int rank);
void r_d(int num,int rank);
void r_i(int num,int rank);
void r_u(unsigned int num,int rank);
void r_x(unsigned int num,int rank, char alpha);
void r_printf(char *format, ...);
void write_main(char str);
int r_strlen(char *str);
int r_intlen(int num);
int num_calc(char *str,int num,int last, int sign);
int num_last(char *str,int num);
int calc_digit(int num);

int main(){
char c_test = 'A';

char s_test[] = "coding is funny";

//r_printf("percent c,s test: %c %c %c %s hello\n",c_test,'b','c', s_test);    
//r_printf("percent d,i,u,x test: %d %i %u %x world\n",0x41,-12312345,123,1234);
//r_printf("percent 3s test :%3s yeah\n","abcdefghijklmnopqrstuvwxyz");

r_printf("asfadf : %-010d asdfasdf\n", -10);

return 0;

}

void r_printf(char *format, ...){
    
    int cnt = 0;
    va_list ap;
    int i,j;
    int start,last;
    int format_num;
    int p_or_m = 1;

    va_start(ap,format);

    for(i = 0; i < r_strlen(format) ; i++){

    start = 0;

      if(format[i] == '%')
	{
		start = i+1;
		if (format[i+1] == '-'){
			p_or_m = 0;
			start+=1;

		}
	 switch(format[i+1])
	
	{

	case 'c':		 	
		r_c((char)va_arg(ap, int),0,'s');
		i+=1;

		break;

	case 'C':
                r_c((char)va_arg(ap, int),0,'l');
                i+=1;

		break;

	case 'd':

		r_d(va_arg(ap,int),0);
		i+=1;

		break;

	case 'i':

		r_i(va_arg(ap,int),0);
		i+=1;

		break;

	case 's':

		r_s(va_arg(ap,char*),0);
		i+=1;

		break;

	case 'x':

		r_x(va_arg(ap,int),0,'s');
		i+=1;

		break;
	case 'X':

                r_x(va_arg(ap,int),0,'l');
                i+=1;

                break;

	case 'u':

		r_u(va_arg(ap,unsigned int),0);
		i+=1;

		break;

	default:


       		last = num_last(format,i);
        	format_num = num_calc(format,start-1,last,p_or_m);

        	switch(format[last+1]){

        	case 's':

                	r_s(va_arg(ap,char*),format_num);
                        if (format_num <0)
                                i+=1;

                	i+=(last+2-start);

                	break;

	        case 'u':

                	r_u(va_arg(ap,unsigned int),format_num);
                        if (format_num <0)
                                i+=1;

                	i+=(last+2-start);

                	break;

	        case 'c':

                	r_c((char)va_arg(ap, int),format_num,'s');
                        if (format_num <0)
                                i+=1;

             		i+=(last+2-start);

	                break;
        	case 'C':
                	r_c((char)va_arg(ap, int),format_num,'l');
     			if (format_num <0)
                                i+=1;

			i+=(last+2-start);

                	break;


	        case 'd':
                	r_d(va_arg(ap,int),format_num);
			if (format_num <0)
				i+=1;
	              	i+=(last+2-start);

        	        break;

	        case 'x':

                	r_x(va_arg(ap,int),format_num,'s');
                        if (format_num <0)
                                i+=1;

                	i+=(last+2-start);

	                break;

                case 'X':

                        r_x(va_arg(ap,int),format_num,'l');
                        if (format_num <0)
                                i+=1;

                        i+=(last+2-start);

                        break;


	        case 'i':

                	r_i(va_arg(ap,int),format_num);
                        if (format_num <0)
                                i+=1;

                	i+=(last+2-start);

	                break;


		default:
			
			break;
		}

	break;

      }

    }
 
  else{
	  write_main(format[i]);
   }
}


	va_end(ap); 
}

int num_last(char *str,int num){


        int i;
        int last = 0;
        int start = num+1;

        int len = r_strlen(str);


	if(str[start] =='-'){		
	       for(i=start+1; i < len; i++){
                

                	if(str[i] >= '0'&& str[i] <= '9'){
				last = i;
                	}

                	else{
                        	break;
                	}
        	}
	}

	else{

        	for(i=start; i < len; i++){


                	if(str[i] >= '0'&& str[i] <= '9'){
                        	last = i;
                	}
                	else{
                        	break;
                	}
        	}
	}

        return last;
}

int num_calc(char *str, int num, int last, int sign){

        int i,j;
        int start = num+1;
        int digit;
        int fac_num=0;

        if (last !=0){

                for (j = last ; j >= start; j--){
                        digit = calc_digit(last-j);
                        fac_num+= digit*(str[j]-'0');
                }

        }

	if(sign ==0)
		fac_num *=-1;

        return fac_num;


}

int calc_digit(int num){

        int i;

        int calc_f=1;

        for(i = 0 ; i < num ; i++){

                calc_f*=10;

        }

        return calc_f;
}


int r_strlen(char *str){

        int cnt = 0;
        int i;
        for(i=0 ; ; i++){
                if (str[i] =='\0'){
                        break;
                }
        cnt++;
        }
        return cnt;
}

void r_c(char str, int rank, char alpha){

        int null = 0x20;
        int i;

        if(rank > 0){
                for(i = 0 ; i < rank-1 ; i++){
                         write_main(null);
                }
        }
	
	if (alpha =='l' && str >='a' && str <='z' )
        	write_main(str-0x20);
	else
		write_main(str);

        if (rank < 0){
                for(i=0 ; i < -1-rank ; i++){
                write_main(null);
                }
        }

}

void r_s(char *str,int rank){

        int null = 0x20;
        int len = r_strlen(str);
        int i;

        if(rank ==0){
                for(i=0 ; i < len ; i++){
                        write_main(str[i]);
                }
        }
        else{
                if (rank > len){

                        for(i = 0;i < rank - len; i++){
                                write_main(null);
                        }
                }
                for(i=0 ; i< len ; i++){
                        write_main(str[i]);
                }
		
	        if (rank < 0){
        	        for(i=0 ; i < (len+rank)*-1 ; i++){
               		write_main(null);
                }
        }


        }
}

void r_d(int num,int rank){

	int real_len = 0;
	int minus = 0x2d;	
	int null = 0x20;
	int num_cpy1;
	int num_cpy2;
	int i,j,len;
	int calc = 1;
	int m_or_p = 1;
	char *int_max = "-2147483648";

	if(num == -2147483648){

		for(i=11; i < rank;i++){
			write_main(null);
		}
	
		for (i=0;i<11;i++){
		write_main(int_max[i]);
		}
	}
	else{

	if(num < 0){
                m_or_p = 0;
                num*=-1;
		real_len+=1;
        }

	num_cpy1 = num;
	num_cpy2 = num;


	len = r_intlen(num_cpy1);
	real_len+=len;

	if (rank > 0){
		for(i=0 ; i < rank-real_len ; i++){
		write_main(null);	
		}
	}

	if (m_or_p == 0){
		write_main(minus);
	} 

	for(j=0 ; j < len-1 ; j++){
		calc = 1;
		for(i=j ; i < len-1 ; i++){
			calc*=10;
		}
		write_main((num_cpy2/calc)%10+'0');
	}
		write_main(num_cpy2%10+'0');
	
	
	
        if (rank < 0){
                for(i=0 ; i < (real_len+rank)*-1 ; i++){
                write_main(null);
                }
        }
	}
}

void r_i(int num,int rank){

        int real_len = 0;
        int minus = 0x2d;
        int null = 0x20;
        int num_cpy1;
        int num_cpy2;
        int i,j,len;
        int calc = 1;
        int m_or_p = 1;
	char *int_max = "-2147483648";

        if(num == -2147483648){

                for(i=11; i < rank;i++){
                        write_main(null);
                }

                for (i=0;i<11;i++){
                write_main(int_max[i]);
                }
        }

	else{

        if(num < 0){
                m_or_p = 0;
                num*=-1;
                real_len+=1;
        }

        num_cpy1 = num;
        num_cpy2 = num;

        len = r_intlen(num_cpy1);
        real_len+=len;

        if (rank !=0){
                for(i=0 ; i < rank-real_len ; i++){
                write_main(null);
                }
        }

        if (m_or_p == 0){
                write_main(minus);
        }

        for(j=0 ; j < len-1 ; j++){
                calc = 1;
                for(i = j ; i < len-1 ; i++){
                        calc*=10;
                }
                write_main((num_cpy2/calc)%10+'0');
        }
                write_main(num_cpy2%10+'0');
	}
}

void r_u(unsigned int num,int rank){

        unsigned int num_cpy1 = num;
        unsigned int num_cpy2 = num;
	int null = 0x20;
        int i,j;
        int cnt = 0;
        int calc = 1;

        for(i = 0 ; ; i++){
                cnt++;
                num_cpy1/=10;
                if(num_cpy1==0){
                        break;
                }
        }

	if(rank > 0){

		for (i = 0; i < rank-cnt; i++){
			write_main(null);
		}

	}

        for(j=0 ; j < cnt-1 ; j++){
                calc = 1;
                for(i=j ; i < cnt-1 ; i++){
                        calc*=10;
                }
                write_main((num_cpy2/calc)%10+'0');
        }
                write_main(num_cpy2%10+'0');

       if (rank < 0){
                for(i=0 ; i < (cnt+rank)*-1 ; i++){
                	write_main(null);
                }
        }

}

void r_x(unsigned int num, int rank, char alpha){

	unsigned int num_cpy;
        int i,mod;
        int num_len = r_intlen(num_cpy);
	int position = 0;
	char minus = 'f';
	char hex[num_len];
	int null = 0x20;
	int p_or_m = 1;
	int ascii;

	if (num < 0){
		num*=-1;
		p_or_m = 0;
	}
	num_cpy = num;
	
	while(1)
	{
		mod = num_cpy % 16;
		if (mod < 10)
		{
			hex[position] = '0'+mod;
		}
		else
		{
			if (alpha =='l')
				hex[position] = 'a'+(mod-10)-0x20;
			else
				hex[position] = 'a'+(mod-10);
		}
		num_cpy/=16;
		position++;
	
		if (num_cpy == 0)
			break;
	}

	if(rank > position && p_or_m){
		
		for(i = 0; i < rank-position; i++)
		{
			write_main(null);
		}		
	}	

	if (rank > position && !(p_or_m)){
	
		for(i = 0; i < rank-8; i++)
		{
			write_main(null);
		}
	}

	if(p_or_m){
		for (i = position-1; i>=0; i--)
		{
			write_main(hex[i]);
		}	
	}

	else{

	for (i = 7; i>=0; i--)

		if (i'9')
				ascii+=0x27;

			if (i==0)
				ascii+=1;
			write_main(ascii);
		}
		else{
			write_main(minus);
		}
	}

        if(rank < 0 && p_or_m){

                for(i = 0; i < -1*(rank+position); i++)
                {
                        write_main(null);
                }
        }

        if (rank < 0 && !(p_or_m)){

                for(i = 0; i < -8-rank; i++)
                {
                        write_main(null);
                }
        }

}

int r_intlen(int num){
	
	int i;
	int num_cpy1 = num;
	int cnt = 0;

	for(i = 0 ; ; i++){
		cnt++;
		num_cpy1/=10;
	
		if(num_cpy1==0){
			break;
		}
	}
	return cnt;
}


printf에게 새삼 고마워진다...



기능이 안되거나 segment fault 뜨면 제보 바랍니다!!!


파일도 함께 첨부합니다


printf.zip


댓글