대외활동/42서울

[42서울] ft_printf 구현 (한 문장으로 구현하는 이진수 보수 연산)

Campus Coder 2024. 6. 21. 19:46
728x90
반응형

서론

과제 이름에서 알 수 있듯이 printf 함수를 구현하는 과제이다. 당연히 printf 함수의 모든 기능을 구현하는 것은 아니고, 문자열 표준 출력과 서식 지정자와 같은 대표적인 기능을 구현하게 된다. 본 과제에서는 va_arg 관련 함수에 대하여 배울 수 있고, 서식 지정자를 어떻게 처리할지에 대해서도 고민해 보며 코딩 실력을 기를 수 있다.

구현

ft_printf

구현한 ft_printf 함수의 메인 로직에 해당하는 두 함수이다. ft_printf 함수에서는 입력받은 문자열을 순서대로 while 루프를 돌아 서식지정자('%')가 아니라면 문자를 하나씩 출력하고, 서식지정자라면 그 뒤에 오는 문자에 따라서 행동을 지정한다. 이때 입력받은 va_list 구조체의 주소를 ft_format_conversion으로 전달한다. 이전 과제를 구현하면서 배웠듯이 주소를 다음 함수로 넘겨야 한다. 그렇지 않으면 변수 ap에 대한 복사본이 호출한 함수에서 사용되어 ft_printf 함수 내에서 va_arg를 통한 va_list ap의 다음 노드 이동이 일어나지 않게 된다. ft_format_conversion 함수에서는 각 서식 지정자에 맞는 함수를 호출하여 서식이 변환된 문자열을 출력한다. 이중 ft_prf_itohex 함수는 다음과 같다.

 

ft_prf_itohex

num += 2L * 16 * 16 * 16 * 16 * 16 * 16 * 16 * 16; 부분이 눈에 들어올 것이다. 이 코드는 대학교 1학년 때 수업 중 배웠던 c의 변수 저장 방식에서 영감을 받아서 작성하였다. 먼저 itohex 함수에서 인자로 들어오는 숫자가 음수라면 그 숫자에 대한 이진수 보수를 출력해야 한다. 2의 보수에 대하여 예시를 통해 살펴보자.

 

한 문장으로 구현하는 이진수 보수 연산

저장 공간으로 4비트를 사용한다고 가정하자(저장 범위 -7~8, 맨 왼쪽 비트는 양수/음수 부호 표현).

 

숫자 -1은 다음과 같이 저장된다.

0001의 보수: 각 비트에 대해 not 연산 -> 1 더하기 -> 맨 왼쪽 비트 음수 부호로 바꾸기

0001 -> 0110 -> 0111 -> 1111

1111

 

여기서 1을 더한다면 10000이 되는데 저장 공간이 4비트이므로 맨 왼쪽 비트가 버려져 저장 공간에 0000이 담기게 된다. 이 연산에서 부호 비트도 변경되면서 -1의 이진수에 1을 더했을 때 0에 해당하는 값으로 모든 비트가 자연스럽게 연산되는 것을 알 수 있다.

저장 공간이 4비트라면 10000, 0000 모두 0을 나타낸다는 것을 기억하자.

 

숫자 8은 다음과 같이 저장된다.

0111

 

숫자 8에서 1을 더한다면 어떻게 될까?

0111 + 1 -> 1000

저장 공간의 값은 -7을 나타낸다. 이를 통해 저장 공간의 양수 값 끝 범위인 8에서 1을 더했을 때 저장 공간의 음수 값 끝 범위인 -7이 된다는 것을 알 수 있다.

 

위 두 예시를 통하여 0에서부터 1을 계속 더하면 아래와 같이 숫자들이 순환하는 특징을 알 수 있다.

0 1 2 3 4 5 6 7 8 -7 -6 -5 -4 -3 -2 -1 0

 

이 특징과 부호 비트가 없는 경우의 값들을 활용하여 음수 값을 이진수의 보수로 출력하기 위한 값을 구하는 식을 작성할 수 있다.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 -7 -6 -5 -4 -3 -2 -1

 

위는 부호 비트를 제외한 4개의 비트가 표현하는 값(0000~1111, 1씩 증가),

아래는 부호 비트를 포함한 4개의 비트가 표현하는 값(0000~1111, 1씩 증가)이다.

음수를 이진수 보수로 출력하고 싶은 경우 위의 값으로 대치해서 이진수로 바꾸어 출력하면 된다.

  • 양수인 경우: 그대로 이진수로 바꾸어 출력
  • 음수인 경우: (부호 비트 제거, 16에서 출력하고자 하는 값 빼주기) 변경 후 이진수로 바꾸어 출력

이 내용을 보고 위에 작성한 코드를 보면 이해가 갈 것이다.

int	ft_prf_itohex(int n)
{
	unsigned long long	num;

	num = n;
	if (n < 0)
		num += 2L * 16 * 16 * 16 * 16 * 16 * 16 * 16 * 16;
}

 

후기

코딩을 공부하는 데 있어 크게 중요하지 않은 부분을 열심히 설명한 것 같지만, 위 코드를 작성하고 동료평가 때 관심을 가지는 사람들이 많았어서 나름 만족스러웠다. 코드를 설명하는 실력도 늘은 것 같고 여러모로 도움이 되는 과제였다. 아래 내용은 앞서 설명한 내용 이외에도 새로 배우게 된 내용이다.

 

이전에 작성한 get_next_line 과제의 헤더파일
이번에 작성한 ft_printf 과제의 헤더파일

헤더파일의 경우 ft_printf 함수와 나머지 유틸 함수를 분리하여 각자 다른 헤더 파일에 담았다. 이전에 작성했던 get_next_line 헤더파일과 대비하여 깔끔해진 모습이다. ft_printf 함수를 사용하기 위해 헤더파일을 선언하면 이외의 불필요한 함수들은 노출되지 않는다.

 

이후 과제도 열심히 구현해보자!

 

 

728x90
반응형