-
[42Seoul] ft_printf 구현의 이론적 배경42Seoul 2022. 8. 2. 00:06
printf의 기능을 카피한 함수를 만드는 과제이다.
이 과제의 주안점은 가변인자함수(variadic fuction)에 대한 이해이다.
가변인자함수란 함수가 받는 인자의 수가 정해져 있지 않은 함수를 말하며, 대표적으로 printf, scanf 가 있다.
가변인자함수는 고정인자, 가변인자로 이루어진다. 고정인자는 반드시 존재해야 하는데, 그 이유는 이 고정인자를 기준으로 가변인자가 배치되기 때문이다.
함수가 받은 인자들은 바이트패딩(byte padding)되어 가변인자 목록에 담긴다.
바이트패딩은 다음을 말한다. CPU는 레지스터의 사이즈 만큼 씩 데이터를 읽는데, CPU가 메모리에 접근을 최소화 할 수 있도록 레지스터의 사이즈에 맞추어 데이터를 배치시키는 것이다. 이에 따라 메모리의 낭비가 발생하나, 속도의 향상을 도모할 수 있다.
인자들은 32비트 운영체제에서는 4의 배수 단위로(4바이트 정렬, 자료형의 크기보다 크거나 같은 4의 배수의 최솟값), 64비트 운영체제에서는 항상 8바이트 단위로 가변인자 목록에 담기게 된다.
다른 말로, 함수가 받는 인자들은 32비트 운영체제에서는 4바이트로, 64비트 운영체제에서는 8바이트로 승격된다고 할 수 있다.
그렇다면, 64비트 운영체제에서 인자의 자료형이 8바이트보다 큰 경우는 어떻게 처리될까?
32비트 운영체제에서는 매개변수가 사이즈와 관계 없이 값으로 복사되는 반면, 64비트 운영체제에서 8바이트보다 큰 인자가 들어올 경우(ex. 구조체)에는 매개변수가 값이 아닌 주소로 전달됨으로써 매개변수를 복사할 때 생기는 오버헤드를 줄일 수 있게 된다.
va_list, va_start(ap, va_list), va_arg(ap, type), va_end 매크로
가변인자함수를 핸들링할 때 필수적으로 활용하게 되는 매크로들이다.
이들은 stdarg.h에 정의되어 있다.
va_list 는 내부적으로 char *로 정의되어 있으며, 이를 통해 복사한 매개변수에 접근할 것이다.
va_start는 va_list로 선언한 포인터(ap, 즉 argument pointer로 명시하는 게 관례인 듯 하다)가 첫 번째 가변인자를 가르키도록 하며, 그 기준점은 마지막 고정인자이다.
va_arg는 ap를 다음 가변인자의 위치로 옮긴 다음 그 주소에서 ap가 이동된 만큼을 뺀 위치의 값을 내놓는다.
이 매크로의 경우 32비트 운영체제와 64비트 운영체제에서 다르게 정의되어있다.
32비트 운영체제의 경우
*((type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type))
이렇게 정의되어 있고,
64비트 운영체제의 경우
1) 자료형이 8바이트 이하일 때
*((type *)((ap += sizeof(_int64)) - sizeof(_int64))
2) 자료형이 8바이트를 초과할 때 혹은 2의 멱승(16, 32, 64 ...)이 아닐 때
**((type **)((ap += sizeof(_int64)) - sizeof(_int64))
두 가지로 나뉜다.
_INTSIZEOF 매크로는 type의 사이즈에 따라 4바이트 정렬(ex. 2바이트는 4바이트, 5바이트는 8바이트, 11바이트는 12바이트)를 내놓으며, 이는 가변인자들이 패딩된 사이즈에 따라 순서대로 함수의 인자 목록에 위치되어 있기 때문에 이에 접근하기 위해 사용한다.
반면, 64비트 운영체제의 경우는 인자들이 _int64, 즉 8바이트로 고정되어 배치됨을 유추할 수 있다.
va_end 매크로는 선언한 va_list 변수를 0(=NULL)로 만들어준다.
이 매크로는 사용하지 않아도 구현에 문제는 없으나, 아키텍쳐 간 호환성을 위해 관례적으로 사용한다고 한다.
'42Seoul' 카테고리의 다른 글
[born2beroot] 리눅스(Debian) 시스템/서버 관련 개념 (0) 2022.10.01 [Born2BeRoot] VDI, VHD, VMDK 포맷의 차이점, 디스크 이미지 파일 (0) 2022.09.20 [Born2BeRoot] 가상머신(Virtual Machine) (0) 2022.09.19 [42Seoul] ft_printf : va_arg(), 바이트패딩에 대한 약간의 고찰 (0) 2022.07.30 [get_next_line] 배경지식(정적변수, 파일디스크립터) (0) 2022.07.14