구현 환경 : 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로 구현해 주면 된다.
#includevoid 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 뜨면 제보 바랍니다!!!
파일도 함께 첨부합니다

댓글