34.5 void 포인터 선언하기
long long *numPtr1;이나 float *numPtr2;는 자료형이 정해진 포인터입니다. 하지만 C 언어에서는 자료형이 정해지지 않은 포인터도 있습니다. void 포인터라는 포인터인데 다음과 같이 void 키워드와 *로 선언합니다.
- void *포인터이름;
void_pointer.c
#include <stdio.h> int main() { int num1 = 10; char c1 = 'a'; int *numPtr1 = &num1; char *cPtr1 = &c1; void *ptr; // void 포인터 선언 // 포인터 자료형이 달라도 컴파일 경고가 발생하지 않음 ptr = numPtr1; // void 포인터에 int 포인터 저장 ptr = cPtr1; // void 포인터에 char 포인터 저장 // 포인터 자료형이 달라도 컴파일 경고가 발생하지 않음 numPtr1 = ptr; // int 포인터에 void 포인터 저장 cPtr1 = ptr; // char 포인터에 void 포인터 저장 return 0; }
기본적으로 C 언어는 자료형이 다른 포인터끼리 메모리 주소를 저장하면 컴파일 경고(warning)가 발생합니다. 하지만 void 포인터는 자료형이 정해지지 않은 특성 때문에 어떤 자료형으로 된 포인터든 모두 저장할 수 있습니다. 반대로 다양한 자료형으로 된 포인터에도 void 포인터를 저장할 수도 있습니다. 이런 특성 때문에 void 포인터는 범용 포인터라고 합니다.
즉, 직접 자료형을 변환하지 않아도 암시적으로 자료형이 변환되는 방식입니다.
// 포인터 자료형이 달라도 컴파일 경고가 발생하지 않음 ptr = numPtr1; // void 포인터에 int 포인터 저장 ptr = cPtr1; // void 포인터에 char 포인터 저장 // 포인터 자료형이 달라도 컴파일 경고가 발생하지 않음 numPtr1 = ptr; // int 포인터에 void 포인터 저장 cPtr1 = ptr; // char 포인터에 void 포인터 저장
단, void 포인터는 자료형이 정해지지 않았으므로 값을 가져오거나 저장할 크기도 정해지지 않았습니다. 따라서 void 포인터는 역참조를 할 수 없습니다.
ptr = numPtr1; // void 포인터에 int 포인터 저장 printf("%d", *ptr); // void 포인터는 역참조할 수 없음. 컴파일 에러 ptr = cPtr1; // void 포인터에 char 포인터 저장 printf("%c", *ptr); // void 포인터는 역참조할 수 없음. 컴파일 에러
컴파일 결과
error C2100: 간접 참조가 잘못되었습니다. error C2100: 간접 참조가 잘못되었습니다.
void 키워드로는 변수를 선언할 수도 없습니다.
void v1; // void로는 변수를 선언할 수 없음. 컴파일 에러
컴파일 결과
error C2182: 'v1': 'void' 형식을 잘못 사용했습니다.
그런데 역참조도 할 수 없는 void 포인터는 왜 사용할까요? void 포인터는 되는 게 별로 없어 보이지만 실제로 C 언어에서 다양한 형태로 사용되고 있습니다. 예를 들자면 함수에서 다양한 자료형을 받아들일 때, 함수의 반환 포인터를 다양한 자료형으로 된 포인터에 저장할 때, 자료형을 숨기고 싶을 때 사용합니다.
아무래도 void 포인터는 초보자가 이해하기 힘든 부분이라 여기서는 완벽하게 이해하지 않고 넘어가도 됩니다. 'Unit 58 자료형 변환하기', 'Unit 61 함수에서 반환값 사용하기', 'Unit 63 함수에서 포인터 매개변수 사용하기'에서 자세히 설명하겠습니다.