서론
과제 이름에서 알 수 있듯이 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;
}
후기
코딩을 공부하는 데 있어 크게 중요하지 않은 부분을 열심히 설명한 것 같지만, 위 코드를 작성하고 동료평가 때 관심을 가지는 사람들이 많았어서 나름 만족스러웠다. 코드를 설명하는 실력도 늘은 것 같고 여러모로 도움이 되는 과제였다. 아래 내용은 앞서 설명한 내용 이외에도 새로 배우게 된 내용이다.
헤더파일의 경우 ft_printf 함수와 나머지 유틸 함수를 분리하여 각자 다른 헤더 파일에 담았다. 이전에 작성했던 get_next_line 헤더파일과 대비하여 깔끔해진 모습이다. ft_printf 함수를 사용하기 위해 헤더파일을 선언하면 이외의 불필요한 함수들은 노출되지 않는다.
이후 과제도 열심히 구현해보자!
'대외활동 > 42서울' 카테고리의 다른 글
[42서울] so_long 맵 유효성 검사(BFS) (0) | 2024.07.22 |
---|---|
[42서울] get_next_line 구현 (메모리 누수 잡기, 구현 tip) (1) | 2024.07.21 |
[42서울] Libft 함수 정리와 후기 (0) | 2024.03.20 |
[42서울] push_swap 그리디 알고리즘 (2) | 2024.03.04 |
[42서울] Born2beroot 개념 정리 2 (0) | 2024.03.04 |