C언어에서 %z, %m 등의 사용자 정의 형식 지정자를 구현하는 방법

함수 printf는 C 표준 라이브러리에서 가장 일반적으로 사용되는 포맷 출력 함수 중 하나입니다. 이 함수는 포맷 문자열을 분석하여 지정된 유형에 따라 데이터를 표준 출력 스트림(stdout)으로 전달합니다.

가변 인수의 구현 원리

printf 함수는 가변 인수 목록(variadic arguments)을 사용하며, <stdarg.h> 헤더 파일에서 정의된 매크로를 통해 인수에 접근할 수 있습니다. 다음은 간단한 printf 호환 함수를 구현한 예제입니다:

#include <stdio.h>
#include <stdarg.h>

void my_print(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);           // 인수 목록 초기화
    vfprintf(stdout, fmt, args);   // vfprintf 호출
    va_end(args);                  // 정리
}

포맷 문자열의 파싱 과정

실행 시 printf는 포맷 문자열을 문자 단위로 스캔하여 % 기호로 시작하는 플레이스홀더를 식별하고, 그 후의 유형 문자(d, s, f 등)에 따라 해당 유형의 데이터를 추출하여 변환합니다.

형식 지정자 데이터 유형 기본 동작
%d int 10진수 문자열로 변환
%s char* 메모리에서 복사하여 출력 버퍼로 전송
%p void* 주소를 16진수로 표현

사용자 정의 형식 지정자의 구현

C99 표준에서는 size_t 타입을 출력하기 위한 %zu 형식 지정자가 도입되었습니다. 이를 사용하면 크기를 올바르게 출력할 수 있습니다.

#include <stdio.h>

int main() {
    size_t sz = 512;
    printf("Size: %zu\n", sz);     // %zu 사용
    return 0;
}

%m 형식 지정자의 구현

%m 형식 지정자는 현재 errno 값에 해당하는 오류 메시지를 출력합니다. 이는 strerror(errno)와 동일한 효과를 제공합니다.

#include <stdio.h>
#include <errno.h>

int main() {
    FILE *fp = fopen("/nonexistent/file.txt", "r");
    if (!fp) {
        printf("Error: %m\n");     // %m 사용
    }
    return 0;
}

출력 제어의 고급 기능

포맷 지정자를 사용하여 폭(width), 정밀도(precision) 및 정렬(alignment)을 조절할 수 있습니다. 예를 들어:

printf("|%10s|\n", "Hello");      // 오른쪽 정렬, 폭 10
printf("|%-10s|\n", "Hello");     // 왼쪽 정렬, 폭 10
printf("|%8.2f|\n", 3.14159);    // 총 폭 8, 소수점 아래 2자리

이 코드들은 각각 문자열과 부동 소수점 숫자에 대한 다양한 출력 형식을 보여줍니다.

태그: C Printf format-specifiers variadic-functions error-handling

6월 28일 00:12에 게시됨