[ft_printf]

James An·2021년 4월 1일
0

42SEOUL

목록 보기
5/11
post-thumbnail

0. 시작 전 알아두어야할 내용

0.1 가변인자 (va_list)

  • printf는 입력하는 인자의 수 제한이 없다. 따라서 가변인자로 받아처리를 진행해야함.
  • <stdarg.h>
     int printf(const char *format, ...);
     ft_printf("%d, %s, %c", 123, 'a', "abc");
  • va_list ap; // 가변 인자 목록 포인터
  • va_start(ap, args); // 가변 인자 목록 포인터 설정.
  • ap는 첫 번째 가변인자 값을 가져온다.
  • va_end(ap); // 가변 인자 목록 포인터를 NULL로 초기화

0.2 플래그 (flag)

  • printf 기본 정렬은 오른쪽 정렬
  • ' - ': 오른쪽 정렬 대신 왼쪽 정렬
  • ' 0' : 공백 대신 0을 추가함. // c, s, p는 사용하지 않음 (숫자, %만 사용)

0.3 서식지정자 (specifier)

others

  • c : 문자
  • s : 문자열
  • p : 포인터

num

  • d(i) : 부호 있는 10진 정수 d와 i의 차이점
  • u : 부호 없는 10진 정수
  • x(X) : 부호 없는 16진 정수 소문자(대문자)

1. ft_printf flow

  • https://user-images.githubusercontent.com/46778769/110093192-c4ec5880-7ddd-11eb-9bb6-44e54a92e91d.png
unsigned behavior
  • printf에서 발생하는 unsigned behavior에 대해서는 ft_printf에서 고려하지 않았다. 3개의 테스터에서 문제되는 부분 찾을 수 없었음.
  • ex) "%***d"처럼 별 여러개, "%d"에 문자 넣기, "%123@"처럼 올바르지 않은 서식지정자 넣기 등

process

  • process -> %를 만나면 flag 초기화 및 flag 탐색 -> 서식지정자 탐색 및 flag에 따라 출력 진행
  • process -> %를 못 만나면 문자를 하나씩 출력한다.

Return value

  • printf의 리턴값은 출력되는 문자의 개수이다.

2. specifier

c

  • 문자 처리
  • ' - ' : 왼쪽 정렬 // 값 출력 후 width 적용

s

  • ' - ' : 왼쪽 정렬
  • ' 0 ' : 너비 옵션에 맞춰 빈자리에 0 추가. - 옵션이 있으면 왼쪽 정렬 실행
  • prec > len인 경우 공백만 신경씀. // prec이 len보다 작아야 문자열을 자름. 이런 경우엔 prec = len으로 생각했다.
  • 문자열 출력은 크게 3단계로 이루어져있다.
printf("%10.5s", "abcdefg");

1. precision 적용: [abcdefg] → [abcde] 

precision과 len의 차이만큼 공백을 패딩해서 출력한다.

2. 위 숫자 전체와 width 비교: [abcde] → [     abcde]

width와 (len+패딩)의 차이만큼 blank를 출력한다.

1와 2에서 출력한 글자 수(cnt) 리턴

d, i

  • 부호를 고려한 10진 정수로 구현.
  • prec > len보다 커야 zero padding이 붙는데 크지 않다면 prec = len으로 생각했다.
  • 숫자 출력은 크게 3단계로 이루어져있다.
printf("%10.5d", 123);

1. itoa 적용: 숫자 123 → 문자열 "123"

2. precision 적용: [123] → [00123] 

precision과 len의 차이만큼 0을 패딩해서 출력한다.

3. 위 숫자 전체와 width 비교: [00123] → [     00123]

width와 (len+패딩)의 차이만큼 blank를 출력한다.

2와 3에서 출력한 글자 수(cnt) 리턴
  • ' - ' flag가 켜져있으면 왼쪽 정렬이므로, 값 출력 -> 공백 출력 순으로 구현.
  • ' - ' flag가 꺼져있다면 오른쪽 정렬이므로 공백 출력 -> 값 출력 순으로 구현.
  • 출력 숫자가 음수인 경우, 0패딩과 공백을 출력하는 flag에 따라 -를 출력하는 방법으로 구현.
  • -2147483648의 경우 pf_itoa에서 예외적으로 처리했기 때문에 본 함수에도 예외로 처리했음.
flag에 따라 -가 다르게 붙어야하는 이유

ft_printf("%010d", -123);   // -000000123
ft_printf("%010.d", -123);  //      -123
ft_printf("%010.1d", -123); //       -123
ft_printf("%010.5d", -123); //     -00123
ft_printf("%-10.5d", -123); // -00123    

u

  • 부호를 고려하지 않은 10진 정수로 구현. unsigned int 범위이다.
  • unsigned int 0 ~ 4,294,967,295
  • 4,294,967,295u의 경우를 고려해 인자의 범위를 4,294,967,295 + 1로 구현.

x, X

  • 부호를 고려하지 않은 16진 정수로 변환 후 출력.

p

  • 포인터의 주소를 받아 16진 정수로 변환 후 출력. 출력값 앞에 "0x" 붙이는 점을 유의해야한다.

%

  • char와 동일하게 구현하였으나 zero flag가 적용된다는 점만 다르게 구현.
  • ' - ': 왼쪽 정렬
  • ' 0 ': 너비 옵션에 맞춰 빈자리에 0 추가. - 옵션이 있으면 왼쪽 정렬 실행

3. 참고 사이트

4. 1트 실패

deepthought 결과

test_s: [ok]
test_d: [ok]
test_p: [ok]
test_x: [ok]
test_i: [ok]
test_u: [ok]
test_c: [ok]
test_mix: [ko]
  • mix ko가 나온 이유는?
  • 두개의 인자를 받아올때 앞에 있는 값이 음수값일때 틀린부분?
  • 아래 결과를 통해 일부 음수의 출력 부분에 문제가 있거나 flag에 이상이 있을 수 있다고 판단했다.
    [printf와 ft_printf에서 음수값이 다른 부분이 있었다.]
    
    ## no flag
	printf("d: %d, d: %i \n", -2147483647, -214748);
	ft_printf("d: %d, d: %i \n", -2147483647, -214748);
    
    
        d: -2147483647, d: -214748 
	d: -7, d: -214748
    -----------------------itoa 수정 후------------------------
    	d: -2147483647, d: -214748 
	d: -2147483647, d: -214748
    
    ## no prec, 5 width 
        printf("d: %5d, d: %5d \n", -2147483647, -214748);
	ft_printf("d: %5d, d: %5d \n", -2147483647, -214748);
    
    	d: -2147483647, d: -214748 
	d:    -7, d: -214748 
    -----------------------itoa 수정 후------------------------
    	d: -2147483647, d: -214748 
	d: -2147483647, d: -214748 
    
    ## prec 5, no width
    	printf("d: %.5d, d: %.5d \n", -2147483647, -214748);
	ft_printf("d: %.5d, d: %.5d \n", -2147483647, -214748);
    
        d: -2147483647, d: -214748 
    	d: -2147483647, d: -214748 
    
    ## no prec, width 5 zero 
    	printf("d: %05d, d: %05d \n", -2147483647, -214748);
	ft_printf("d: %05d, d: %05d \n", -2147483647, -214748);
    
    	d: -2147483647, d: -214748 
	d: -2147483647, d: -214748 
    
    ## no prec, width 5 minus
    	printf("d: %-5d, d: %-5d \n", -2147483647, -214748);
	ft_printf("d: %-5d, d: %-5d \n", -2147483647, -214748);
    
    	d: -2147483647, d: -214748 
	d: -7   , d: -214748 
    -----------------------itoa 수정 후------------------------
    	d: -2147483647, d: -214748 
	d: -2147483647, d: -214748 
  • 음수 출력에 대한 flag 조건을 잘못 설정했다면, 테스터에서 당연히 걸렸을 것이라 생각해 테스트 케이스에 문제가 있는 음수에 대해 테스트 케이스를 바꾸어 진행해보았다
  • 테스트 케이스의 값을 -2147483647로 지정
1트 당시 pft 테스터기에서 문제 없었음.
[ 테스트 케이스의 값을 바꾸자 귀신같이 fail이 뜨기 시작했다. 아마 뮬리넷은 여기서 fail을 주지 않았을까 ]

[ type d ]

Test 191 (d_basic_neg) : FAILED.
    First line of code: {return test("this %d number", -2147483647);}
      expected output : "this -2147483647 number"
      your output     : "this -7 number"
      expected (nonprintable as hex) : "this -2147483647 number"
      actual   (nonprintable as hex) : "this -7 number"

Test 202 (d_width_neg_exactfit) : FAILED.
    First line of code: {return test("%5d", -2147483647);}
      expected output : "-2147483647"
      your output     : "   -7"
      expected (nonprintable as hex) : "-2147483647"
      actual   (nonprintable as hex) : "   -7"

Test 209 (d_width_neg_exactfit_lj) : FAILED.
    First line of code: {return test("%-5d", -2147483647);}
      expected output : "-2147483647"
      your output     : "-7   "
      expected (nonprintable as hex) : "-2147483647"
      actual   (nonprintable as hex) : "-7   "

Test 211 (d_width_neg_nofit_lj) : FAILED.
    First line of code: {return test("%-4d", -2147483647);}
      expected output : "-2147483647"
      your output     : "-7  "
      expected (nonprintable as hex) : "-2147483647"
      actual   (nonprintable as hex) : "-7  "

[type i]

Test 268 (i_basic_neg) : FAILED.
    First line of code: {return test("this %i number", -2147483647);}
      expected output : "this -2147483647 number"
      your output     : "this -7 number"
      expected (nonprintable as hex) : "this -2147483647 number"
      actual   (nonprintable as hex) : "this -7 number"

Test 271 (i_basic_onlyneg) : FAILED.
    First line of code: {return test("%i", -2147483647);}
      expected output : "-2147483647"
      your output     : "-7"
      expected (nonprintable as hex) : "-2147483647"
      actual   (nonprintable as hex) : "-7"

Test 286 (i_width_neg_exactfit_lj) : FAILED.
    First line of code: {return test("%-5i", -2147483647);}
      expected output : "-2147483647"
      your output     : "-7   "
      expected (nonprintable as hex) : "-2147483647"
      actual   (nonprintable as hex) : "-7   "
  • 기존에 사용한 pf_itoa는 8자리까지는 이상없이 출력되었지만 9자리 수 부터 문제가 발생했다.
[printf 결과값]

d: -1, i: -1

d: -11, i: -11

d: -111, i: -111

d: -1111, i: -1111

d: -11111, i: -11111

d: -111111, i: -111111

d: -1111111, i: -1111111

d: -11111111, i: -11111111

d: -111111111, i: -111111111

d: -1111111111, i: -1111111111

[ft_printf 결과값]

d: -1, i: -1

d: -11, i: -11

d: -111, i: -111

d: -1111, i: -1111

d: -11111, i: -11111

d: -111111, i: -111111

d: -1111111, i: -1111111

d: -11111111, i: -11111111

d: -1, i: -1   // 터짐

d: -1, i: -1  // 터짐
  • pf_itoa를 수정 후 동일한 환경에서 테스트 해보았다.
[pft 테스터기]

./test d: Tests completed. 80/80 tests passed.
./test i: Tests completed. 77/77 tests passed.

[출력 값]

d: -1, i: -1

d: -11, i: -11

d: -111, i: -111

d: -1111, i: -1111

d: -11111, i: -111111

d: -1111111, i: -1111111

d: -11111111, i: -11111111

d: -111111111, i: -111111111

d: -1111111111, i: -1111111111
  • pf_itoa를 수정 후 문제되는 부분이 수정됨을 알 수 있었다.
  • pft 테스터를 통해 mix하는 부분에서 문제가 없었으나 int의 음수 부분이 9자리 ~ 10자리인 경우 -2147483648을 제외하고 제대로 출력되지 않고 있었다.
profile
born 2 code :)

0개의 댓글