article thumbnail image
Published 2022. 8. 19. 14:54

설명에 들어가기 전 후기

42 Seoul을 시작하기 전에는 c를 사용하며 굉장히 많이 사용하는 함수였지만, 42 Seoul에서는 강력하게 금지하여 사용하지 못했던 printf를 드디어 구현하는 프로젝트였다.

ft_printf를 구현하기 위해 가변 인자에 대한 개념을 새롭게 알게 되었다.

 보너스를 구현하지 않았지만, 보너스를 구현하신 분의 평가를 다녀오며 printf에서 사용하는 다양한 플래그들을 만나볼 수 있었다.

printf는 단지 인자를 받아서 해당하는 형식에 맞게 출력해주는 함수라고만 단순히 알고있었는데, 다양한 플래그들을 통해 많은 방법으로 출력하는 함수임을 처음 알게 되었다.

보너스를 하지 않으니 구현하는 데에는 크게 어렵지 않았다.

단지 unsigned 형에 음수가 나올때의 처리 방법만이 조금 까다로웠을 뿐이다.

이 문제를 해결하기 위해 음수를 일일이 다 넣어보고 값이 어떻게 변수에 저장되는지 살펴보았다.

unsigned int형의 변수에 -1을 넣어서 printf 함수를 통해 %d로 출력하면 그대로 -1이 %u를 넣었을 때는 4294967295라는 수가 나온다.

이유는 아무리 unsigned int형의 변수 값이 -1이라 하더라도 서식 지정자가 %d이면 강제로 %d에 맞게 캐스팅 되므로 -1이 나오고, 서식 지정자가 %u이면 2의 보수 연산으로 인한 결과값인 4294967295가 나오게 된 것이다.

따라서 이 문제를 해결하기 위해 서식 지정자가 %u일때는 unsinged int형으로 가변 인자를 받아주되, 인자를 받아 write를 하는 과정에서 unsigned long long형으로 사용할 수 있는 값의 범위를 더 넓혀 2의 보수 값이 제대로 다뤄질 수 있도록 하였다. 

평가를 하면서 운영체제를 깊게 공부하신 분께서 write함수는 시스템 콜이며, 시스템에 직접 명령을 내리므로 많이 호출을 하면 그만큼 시스템에 무리가 간다는 것을 알려주셨다.

운영체제를 전공 수업에서만 배우고 까먹었던 지난날이 후회되는 순간이었다.

42 Seoul 과제를 진행하면서 코드의 최적화와 프로그램의 성능을 위해 더욱더 공부해야겠다.

 

 

프로젝트 소개

printf 함수 구현하기

 

printf

int printf(const char *str, ...);

C언어의 표준 출력 함수로, 여러 종류의 데이터를 다양한 서식에 맞춰 출력

printf의 f은 서식화된(formatted) 출력을 지원한다는 의미

%와 함께오는 서식 지정자를 통해 출력할 데이터를 해당 서식에 맞춰 출력

 

가변 인자

printf 함수의 두 번째 인자로 사용되는 ... 은 가변 인자

가변 인자는 인자의 수가 정해지지 않을때 사용

포인터의 작용으로 이뤄지며, 인자의 개수가 몇 개인지 모르기 때문에 스택에 쌓았다가 하나씩 빼서 사용

 

va_list 

가변 인자의 시작 주소를 가리킬 포인터

가변 인수들을 저장하려는 가변 저장 공간

 

va_start

void va_start(va_list ap, variable_name);

va_list로 만들어진 포인터에게 가변 인자 중 첫 번째 선택적 인수(variable_name)의 주소를 가르쳐 줌

ap 포인터를 초기화

매개변수

ap : va_list로 만든 포인터

variable_name : 마지막 고정된 필수 인수

 

=> ap의 주소값 + variable_name의 크기 = 가변 인자의 첫 주소

 

va_arg

var_type va_arg(va_list ap, var_type);

ap로 지정된 위치에서 var_type 값을 검색하고 다음 인수를 가리키도록 ap를 증가

va_list의 포인터를 다음 가변인자로 이동시킴

매개변수

ap : va_list로 만든 포인터

var_type : int, long과 같은 타입

반환값

현재 인수를 리턴

 

va_copy

void va_copy(va_list dest, va_list src);

인수 목록 src을 dest로 복사

 

va_end

void va_end(va_list arg_ptr);

모든 인수가 검색 된 후 arg_ptr을 NULL로 설정

사용한 가변인자 변수를 끝낼 때 사용

 

 

서식 지정자

%c

단일 문자 1개 출력

char이 아닌 아스키 코드 값을 받기에 int

 

%s

문자열 출력

char *

 

%p

포인터 주소 출력

앞에 0x이 붙고, 16진수로 표현

void *

 

%d

10진수 정수를 출력

signed 10진수를 입력 받음

int

 

%i

10진수 정수를 출력

10진수 / 8진수 / 16진수를 입력 받음

int

 

%u

부호 없는 10진수 숫자를 출력

만일 음수가 들어가면 2의 보수로 캐스팅 되므로 unsigned int보다 더 큰 수가 들어가기에 long long으로 함수 내에서 다뤘음

unsigned int

 

%x

소문자를 사용하여 숫자를 16진수로 출력

만일 음수가 들어가면 2의 보수로 캐스팅 되므로 unsigned int보다 더 큰 수가 들어가기에 long long으로 함수 내에서 다뤘음

unsigned int

 

%X

대문자를 사용하여 숫자를 16진수로 출력

만일 음수가 들어가면 2의 보수로 캐스팅 되므로 unsigned int보다 더 큰 수가 들어가기에 long long으로 함수 내에서 다뤘음

unsigned int

 

%%

%를 출력

 

 

보너스 파트 (구현 X)

플래그 (flag)

기본적으로 출력되는 형태에 조금 더 자세히 지정할 수 있게 함

-

필드에서 값을 왼쪽으로 정렬 (기본 설정은 오른쪽 정렬)

0

변수의 길이가 width보다 작으면, 공백을 0으로 채움

.

소수점 이하 자리 수를 결정

*

필드의 폭(width)을 결정

#

o, x, X 서식 문자들과 사용되면 출력되는 값 앞에 각각 0, 0x, 0X가 붙음

+

출력 결과 값이 양수인 경우 앞에 + 기호를 붙여서 출력 (기본 설정은 음수 앞에만 -)

 

폭 (width)

출력할 값의 최소 폭을 지정

출력할 값보다 폭이 더 크면 공백을 0으로 채움

 

 

 

'42 Seoul' 카테고리의 다른 글

[42 Seoul] Born2beroot - User, Hostname, Partitions  (0) 2022.09.05
[42 Seoul] Born2beroot - 프로젝트 개요  (0) 2022.09.01
[42 Seoul] Libft - Bonus  (0) 2022.08.02
[42 Seoul] Libft - Part 2  (0) 2022.08.02
[42 Seoul] Libft - Part 1  (0) 2022.08.02
복사했습니다!