42Seoul [ft_printf]
ft_printf
이 프로젝트는 꽤 단순합니다. 여러분은 printf 함수를 직접 구현하시면 됩니다. 희망컨대 여러분들은 cheater로 지목될 수 있다는 두려움 없이 추후 프로젝트에서 이것을 재활용할 수 있습니다
이 포스팅은 보너스 파트를 구현하지 않았습니다.
- norm규칙을 준수할 것
- 뮬리넷을 통과해야지 컴파일 된다.
- 메모리 관련 누수는 허락하지 않는다.
- 전역변수사용 금지
- libft는 프로젝트에 사용가능
이번 과제는 자주사용하는 libc의 printf함수를 내가 직접 구현하는 과제이다.
처음 libft와 같이 makefile을 통한 컴파일과 라이브러리 생성을 요구한다.
실제 printf로 채점을 진행하니 구조 자체를 완벽하게 이해하는 것이 중요(man 3 printf)
문자열함수를 유용하게 사용하여 읽어들인 문자열을 해석하여 write함수로 찍어낸다.
시작하기 전 필요한 정보들
시작하기 앞서서 printf가 뭔지 알고 동작방식을 이해한다면 크게 어럽지 않다.
printf는 print formatted, 출력 서식을 지정하여 형식에 맞게 출력해주는 함수이다.
c언어로 코딩을 하게 되면 가장 먼저 접하게 되는 함수로 printf("Hello World");
매우 유명하다.
printf작동방식
printf의 기본모습이다.
보기와 같이 가변인자로 원형이 선언된 모습
내부 동작은 다양한 stdarg.h에 정의된 매크로를 사용하여 동작하며 int형으로 출력되는 문자열의 길이를 나타낸다.
int main()
{
int len;
len = printf("한글입니다.");
printf("%d", len);
return 0;
}
그렇다면 위의 코드의 출력값은 6이 되어야 정상인가..?
출력값
한글입니다.16
문제자체를 풀때는 크게 상관없지만 한글은 2바이트나 3바이트로 처리하기 때문에 반환값이 다른걸 알 수 있다.
따라서 내부적으로도 1바이트씩 읽어서 사용 즉, 아스키코드값으로 동작함을 알 수 있다.
가변인자
사용하기 위해선 stdarg.h에 정의된 매크로를 사용해야 한다.
가변인자는 해석 그대로 개수가 정해지지 않은 인자 즉, 몇개의 값이 들어올지 모를 경우에 사용한다.
오버로딩과 비슷하지만 들어오는 인자의 수가 정해지지 않고 매번 함수에 들어가는 인수의 개수가 변화한다.
제네릭이나 오버로딩과 비슷하다고 생각할 수 있지만 가변인자를 사용한 함수는 자료형은 고정되며 인자의 수가 달라질 수 있다는 점에서 다르다.
void va_test(int args, ...)
가변인자함수의 기본 사용법
...
이 가변인자 표시법이다.
- va_list: 가변인자의 메모리 주소를 저장하는 포인터
- va_start: 가변인자를 가져올 수 있도록 포인터를 지정해주는 포인터 초기화 함수
- va_arg: 가변인자 포인터에서 특정자료형만큼 반환하는 함수
- 값을 반환하고 해당 자료형 크기만큼 이동(순방향)
- 객체지향의 반복자같이 작동
- va_end: 가변인자 포인터 null초기화 함수
va_arg의 두번째 인자가 형식자인 이유는 내부적으로 매크로함수이기 때문에 sizeof를 통해 캐스팅이 이루어 진다.
va_arg 2번째인자 자료형 크기만큼 이동한다는 뜻은 4바이트의 경우 배열이동과 같이 4바이트를 이동하여 다음 시작지점을 알려준다는 것
#include <stdio.h>
#include <stdarg.h>
void test(int args, ...)
{
va_list ap; // 가변인자 목록 포인터 선언
va_start(ap, args); // 가변인자 포인터 할당
for (int i = 0; i < args; i++)
{
int num = va_arg(ap, int); // 값을 가져오고 반복자처럼 뒤 자료형 크기만큼 메모리 이동
printf("%d ", num);
}
va_end(ap); // 가변인자 포인터 초기화
printf("\n");
}
int main()
{
test(2, 0, 42);
test(4, 2, 42, 123, 555);
return 0;
}
서식지정자
ft_printf에서 요구되는 서식지정자 양식
서식지정자 | 출력 형태 |
---|---|
%c |
단일 문자(Character) 한개를 출력 |
%s |
문자(String)열을 출력 |
%p |
void* 형식의 포인터 인자를 16진수로 출력합니다. |
%d |
10진수 숫자를 출력합니다. |
%i |
10진수 정수를 출력합니다. (scanf일 경우에는 8/10/16받음) |
%u |
부호 없는 10진수 숫자를 출력합니다. |
%x |
소문자를 사용하여 16진수를 출력합니다. |
%X |
대문자를 사용하여 숫자를 16진수로 출력합니다. |
%% |
퍼센트 기호를 출력합니다. |
int len;
len = 0;
printf("%c\n", 'A');
printf("%s\n", "ABCDEFU");
printf("%p\n", &len);
printf("%d\n", 42);
printf("%i\n", 4878);
printf("%u\n", -123);
printf("%x\n", 42);
printf("%X\n", -42);
printf("%%\n");
return(0);
위 코드를 동작시키고 동작방식을 이해하는것이 중요..!
구현방법
가장 먼저 이 함수에 대한 원형은 문자열과 가변인자로 나뉘어 매개변수로 전달된다.
int ft_printf(const char *format, …)
이 함수내부에서
%
서식지정자를 발견한 경우와 발견하지 못한 경우로 구분- 서식지정자가 아닌 경우 해당 문자열 출력
- 서식지정자가 발견된 경우 해당 서식지정자에 맞는 형식을 가변인자에서 순차적 접근하여 출력
위 과정처럼 간단하게 해결된다.
댓글남기기