가변인자와 형식지정자

개요

가변인자의 개념과 사용방법에 대해서 알아보고 printf에 대해서 알아보겠다.




printf() 함수


printf 함수는 사용자가 프로그램을 통해 원하는 내용을 출력하고 싶을 때 사용하는 것이다.

어떤 변수를 출력하라고 요청할 때 printf()에게 내리는 지시는 변수의 데이터형에 따라 다르다.

출력하고 싶은 데이터를 특정 포맷으로 변환해야 하는지 지정하기 때문에, 변환 지정이라고 부른다.

변환 지정자 혹은 형식 지정자라고 불리는데 흔히 사용하는 %d, %s와 같은 것이다.

컴퓨터는 2진수로 데이터를 처리하는데, 그 2진수 값을 형식지정자에 따라서 변환하여 출력한다.

형식 지정자


%a

부동소수점 수 16진수 p-표기


%c

단일문자


%d

부호 있는 10진 정수


%e

부동소수점 수, e-표기


%f

부동소수점 수 10진 표기


%i

부호 있는 10진 정수


%o

부호 없는 8진 정수


%p

포인터


%s

문자열


%u

부호 없는 10진 정수


%x

부호 없는 16진 정수 소문자로 출력


%%

퍼센트 기호 출력




printf() 사용 형식


printf("Control-string", item1, item2, ...);

item

item1, item2, …는 출력할 항목들을 나열한 것이다. 변수, 상수, 표현식이 올 수 있다.

control-string

Control-string은 출력할 내용들과 item들의 대한 형식 지정자가 들어있는데 각 항목마다 대응되는 하나의 형식지정자가 존재해야한다.

사용자는 넣고 싶은 개수 만큼 넣으면 된다.

그렇다면 printf 함수는 사용자가 몇개나 넣을지 모른다.

그래서 printf 함수의 인자는 가변인자 함수로 되어있다.




가변인자


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

printf 함수의 기능을 구현해 보았다. 그 함수의 프로토 타입이다.

무조건 고정 매개 변수가 존재해야한다. ft_printf 함수의 고정 매개 변수는 const char *str이다.

가변인자를 다루는 자료형은 따로 있다. va_list인데 가변인자 포인터를 만들어준다.


va_start

그렇다면 이 포인터가 가변인자를 가리키도록 설정해야 하는데 이를 위해 va_start매크로이다.

첫번째 매개변수로 초기화 시킬 가변인자 포인터를 넣고, 두번째 매개변수로는 고정매개변수를 넣으면 된다.

이후 가변인자 포인터는 고정매개변수의 바로 뒤를 가리킨다. 즉 가변인자의 맨 처음을 가리키게 된다.


매크로와 함수의 차이점

함수는 중복되는 코드를 줄여주고 스택 프레임안에서 작업을 처리하기 때문에 메모리 공간을 잡아먹는다.

그렇기 때문에 파일의 크기를 줄여주고 코드의 양을 줄일 수 있다. 그러나 메모리 공간 할당 문제 때문에 실행속도가 늦어진다.

이에 반면 매크로는 전처리 과정에서 실행되며 컴파일 과정에서는 직접 코딩한 것처럼 처리하는 기능이다.

그렇기 때문에 코드의 길이가 늘어나고 최종적인 파일 크기가 늘어나며 스택을 사용하지 않기 때문에 재귀와 같은 기능을 사용할 수 없지만 공간할당 문제에서 자유로워 실행 속도가 빠르다.

두가지를 적절히 사용하면 좋은 코드가 될 것이다.


va_arg

va_arg 매크로는 두개의 파라메터를 가지는데 첫번째 매개변수는 가변인자 포인터를 넣고 두번째 매개변수는 불러올 데이터의 자료형을 넣으면된다.

그렇다면 가변인자 포인터는 데이터의 자료형만큼 이동한 다음 기존 주소부터 현재 주소까지의 데이터를 불러온다.


va_end

가변인자를 다 읽어오면 가변인자 포인터를 널로 초기화 시켜주면서 포인터 해제한다.






형식 지정자 앞에 숫자


형식 지정자 앞에, %뒤에 숫자를 입력하면 결과물의 출력 길이를 조절할 수 있다.

숫자

최소 필드 너비를 의미한다. 예를 들어 %4d이면 최소 4개의 필드에 출력되어야한다는 뜻이며 개수가 맞지 않으면 공백을 출력한다.

.숫자

정밀도를 의미하는데 %e, %f와 같은 경우 소수점을 출력하는데 원하는 만큼의 소수점을 입력하면 된다. 예를 들어 .2%f 는 소수점 두자리까지만 출력하라는 의미이다.




플래그


  • - : 항목이 왼쪽 정렬로 출력 된다.
  • + : 부호 있는 수를 출력할 때, 해당 숫자의 부호를 같이 출력한다.
  • 스페이스 : 부호 있는 수를 출력할 때, 양수이면 부호 없이 스페이스를 하나 붙이고, 음수이면 -를 붙인다.
  • # : 형식지정자에 대응하는 형식을 사용한다. %o는 0을 하나 붙이고 %x는 0x를 붙인다.




전달인자의 메커니즘


printf()도 함수이기 때문에 가변인자의 값들을 스택에 넣는다.

컴퓨터가 스택에 넣을 때, 형식지정자는 관련이 없고 변수들의 데이터 자료형에 따라 메모리를 설정한다.

그렇게 설정한 메모리를 가변인자 포인터로 처리한다.




printf()의 리턴값


printf() 함수는 자신이 출력한 문자의 수를 리턴한다. 출력중에 에러가 발생한 경우에는 음수를 리턴한다.