본문 바로가기

언어/C

[C언어] What is printf()?

728x90
반응형

 

 

INDEX

1. printf의 f

2. 왜 int형으로 선언되었을까?

3. (const char* restrict format,...)의 의미는?

4. 가변 인자란?

 

 

 

int printf(const char* restrict format, ...)

printf()는 함수이다. C언어를 접한 초창기 때부터 항상 사용했던 것이라 함수라는 의심을 아예 하지 못하였다. 하지만 지금 와서 다시 생각해 보면 그냥 헤더 파일에서 지원해 주는 것들은 전부 다 함수이다. 인자를 통해 특정 목적을 수행해 주는 함수, 즉 printf() 또한 같은 원리로 동작한다. 하지만 구체적으로 어떻게?

 

먼저 printf()함수란 뭐인지 알아보자. "사용자가 프로그램과 대화하기 위해 사용하는 함수(입출력, I/O)에서 Output 역할을 맡고 있는 함수"로 정의할 수 있다. 하지만 함수라면 원형이 존재해야 하지 않는가? 그렇다면 그 원형에 대해 살펴보자

 

원형(prototype)

int printf(const char* restrict format, ...);

위와 같이 생겼다. 물론 사용을 위해서는 #include <stdio.h>를 선언해야 하는 것은 기본이다. 원형을 살피다 보면 궁금한 점이 몇 개 생기는데 아래에서 확인해 보자.

 

1. printf의 f

print 뒤에 f의 의미는 formatted의 약자로 서식화된 출력을 지원한다는 의미이다. 그렇다면 여기서 서식이란 무엇일까? 틀 잡아주기로 이해하면 편한데, 즉 우리가 똑같은 데이터를 입력해도 원하는 지정된 형식으로 출력을 조작할 수 있다는 것이다. 예를 들어 'A'를 printf함수에 인자로 전달했어도 서식에 따라(%c->A, %d->65) 출력의 결과가 달라지는 것과 같은 것이다. 

 

 

 

2. 왜 int형으로 선언되었을까?

출력 자체가 int형이라는 뜻이 아니다. 우리가 주로 많이 보는 int function(int a) 꼴로 선언되고 return result;을 통해 result를 int형으로 반환하기 위해 int가 사용된 맥락과는 다르다. 그리고 진짜로 int형으로만 출력을 했으면 char, short, float, double 등등은 어떻게 출력하겠는가? 

 

즉 여기서 말하는 받은 인자들에 대한 출력은 printf() 자체에서 수행해 주는 것이고 여기서 int가 하는 역할은 printf()에 의해 출력되는 문자들의 개수이다. 그렇다면 아래의 출력 결과를 예측해 보자.

#include <stdio.h>

int main() {
    int a = 12;
    int b = printf("%d34\n", a);
    printf("%d", b);
}

먼저 printf("%d34\n", a);가 실행 되어 1234가 출력될 것이다 그다음에 '\n'을 포함한 채로 b에는 5가 저장될 것이다. 

 

 

 

3. (const char* restrict format,...)의 의미는?

  • const char* restrict format
    고정 인수 부분이다. 원형의 type(c, s, d, f..)과 개수(서식 지정자 : %)가 분명히 명시되어 있기 때문에 원형 그대로 정확히 전달해야 한다. 또한 전달된 format 문자열의 값을 함수 내에서 변하지 않게끔 하기 위해 const를 사용하였다. const는 데이터의 의도치 않은 변화를 막아준다. 
  • ...
    처음에 봤을 때는 그냥 생략 문구인 줄 알았는데 실제로 기능이 존재한다. 명칭은 가변인자이고 정확한 원리는 아래에서 따로 다루겠다.

 

 

4. 가변 인자란?

받을 수 있는 인자의 개수가 정해져 있지 않음을 뜻한다. 그렇다면 입력받은 숫자들에 대해 합 연산을 실행하는 함수를 가변 인자를 통해 만들어 보자. 

#include <stdio.h>
// 가변 인자를 다루는 기능 제공
#include <stdarg.h> 

int get_sum(int n, ...) {
    // 가변 변수들(...)을 가리킬 포인터. 배열에 char 형태로 저장됨
    va_list ap; 
    int sum = 0;
    // ap 포인터 변수가 첫 번째 가변 인수들을 가리키도록 초기화
    va_start(ap, n); 
    for (int i = 0; i < n; ++i) {
        /* 가변 인자 값이 저장된 배열에서ap가 가리키는 위치를 읽어 반환. 읽고자 하는 값의
         * 타입을 int로 지정*/
        sum += va_arg(ap, int); 
    }
    // ap가 NULL을 가리키도록 만들어줌. 관례적인 표시임
    va_end(ap);
    return sum;
}

int main() {
    printf("%d", get_sum(5, 1, 2, 3, 4, 5)); // 출력 결과 : 가변 인자들의 합인 15
}

여기서 의문이 하나 생긴다. sum+=va_arg(ap, int);에서 int는 타입명이면서 어떻게 함수의 인자로 전달될 수 있는가? 

 

일단 va_arg는 진짜 함수가 아니다! 매크로 함수이기 때문에 va_arg의 두 번째 인자는 sizeof 연산자와 캐스트 연산자로 전달되기 때문에 가능한 일인 것이다. 캐스트 연산자란 변수의 형태를 임시적으로 변환하는 함수이다. 예를 들자면 아래의 코드가 있다.

#include <stdio.h>

int main() {
    printf("%d", (int) 'A'); // 출력 결과 : 65
}

 따라서 캐스트 연산자는 ap에서 읽어 들인 데이터 타입이 원하는 타입인지 보장해 주는 역할을 한다.

 

 

728x90
반응형

'언어 > C' 카테고리의 다른 글

[C언어] 포인터란?  (0) 2024.02.21
[C언어] What is scanf()?  (0) 2023.09.18