C 프로그래밍 언어에서 _Generic 키워드는 서로 다른 데이터 타입에 대해 각각 다르게 동작하는 매크로(MACRO)를 정의할 때 사용됩니다. 이 키워드는 C11 표준에서 새롭게 도입되었으며, 프로그래머가 매크로를 더욱 효율적으로 활용할 수 있도록 도와줍니다.
_Generic의 핵심 동작 원리는 전달된 변수의 데이터 타입을 기준으로 매크로가 어떤 표현식으로 변환될지 결정한다는 점입니다. 마치 C++의 함수 오버로딩과 유사한 기능을 C 언어에서 구현할 수 있게 해주는 셈입니다.
_Generic 기본 문법
매크로를 여러 타입에 대응하도록 선언하는 일반적인 형태는 다음과 같습니다.
#define dec(x) _Generic((x), long double : decl, \ default : inc, \ float : incf)(x)
위 문법처럼 _Generic(제어식, 타입1: 표현식1, 타입2: 표현식2, ..., default: 기본표현식) 형태로 작성하면, 제어식의 타입에 따라 컴파일 시점에 해당 표현식이 선택됩니다.
예제 코드
아래 예제는 전달된 값의 데이터 타입에 따라 서로 다른 숫자를 반환하는 매크로를 정의한 코드입니다.
#include <stdio.h>
#define typecheck(T) _Generic( (T), char: 1, int: 2, long: 3, float: 4, default: 0)
int main(void) {
printf("long 값을 매크로에 전달, 결과는 %d \n", typecheck(2353463456356465));
printf("float 값을 매크로에 전달, 결과는 %d \n", typecheck(4.32f));
printf("int 값을 매크로에 전달, 결과는 %d \n", typecheck(324));
printf("문자열을 매크로에 전달, 결과는 %d \n", typecheck("Hello"));
return 0;
}실행 결과
long 값을 매크로에 전달, 결과는 3 float 값을 매크로에 전달, 결과는 4 int 값을 매크로에 전달, 결과는 2 문자열을 매크로에 전달, 결과는 0
동작 방식 분석
위 코드에서 typecheck 매크로는 인자로 받은 값의 타입을 판별하여 다음과 같이 동작합니다.
- char 타입 → 1 반환
- int 타입 → 2 반환
- long 타입 → 3 반환
- float 타입 → 4 반환
- 그 외 모든 타입(default) → 0 반환
예를 들어 2353463456356465는 int 범위를 초과하므로 long 타입으로 해석되어 3이 출력되고, 4.32f는 float 리터럴이므로 4가 출력됩니다. 반면 문자열 "Hello"는 목록에 없는 타입(char 포인터)이므로 default인 0이 반환됩니다.
_Generic 사용 시 주의사항
- _Generic은 컴파일 타임에 평가되므로 런타임 오버헤드가 없습니다.
- 타입 목록에는 중복된 타입을 지정할 수 없습니다.
- 모든 경우를 커버하기 위해
default항목을 두는 것이 안전합니다. - 배열이나 문자열 리터럴은 자동으로 포인터 타입으로 변환(decay)되므로 주의해야 합니다.
이처럼 _Generic 키워드를 활용하면 하나의 매크로 이름으로 여러 데이터 타입을 지원하는 타입 제네릭(type-generic) 프로그래밍을 C 언어에서도 손쉽게 구현할 수 있습니다. 수학 라이브러리의 tgmath.h가 대표적인 활용 사례입니다.