[C언어] void 포인터(void pointer)개념과 자유로운 형변환, malloc 반환형
void 포인터
void 포인터??
이런 포인터는 처음 들어봤네요~ 분명 void라는 것은 함수 앞에서 반환형이 없을 때 쓰이는 키워드로 아는뎁;
void main은 많이 봤는데...
지금부터 이야기할 주제가 바로 void포인터라고 합니다. 우리는 이제껏 자료형이 정해져있는 포인터 예를 들면
int *a
라는 형태는 봐왔잖아요?
그리고 그 포인터에 주소를 할당하는 방법은 이런 것이죠.
int a=100;
int *b=&a;
이걸 말로 풀어서 설명한다고 하면
b는 a의 주소를 가지고 있고, b를 통해 a를 참조할 수 있는데 그곳에는 int형 데이터가 있다!
라고 말이에요.
우리는 이 말속에서 힌트를 얻을 수 있습니다.
그곳에는 int(정수형)형 데이터가 있다 라는 말을 집중해주세요.
위의 int *를 void *로만 바꾸어 써보고 읽어볼게요.
int a=100;
void *b=&a;
b는 a의 주소를 가지고 있고, b를 통해 a를 참조할 수 있는데 그곳에는 void형 데이터가 있다.
void 형 데이터가 있다....(?) void는 "빈공간"이라는 뜻을 내포하고 있는데요. 컴퓨터는 자료형을 모르기 때문에 빈공간처럼 보는 겁니다.
그러기 때문에 앞으로 우리는 이렇게 읽어야 할 겁니다.
b는 a의 주소를 가지고 있고, b를 통해 a를 참조할 수 있는데 그곳에는 알 수 없는 자료형 데이터가 있다.
이 형태 그대로 데이터를 참조하면 컴퓨터는 "아 몰랑!" 합니다.
printf("%d\n", *b); //오류
얼마나 참조해야하는지 알 수 없기 때문입니다. void는 단순히 주소값만을 가지고 있습니다.
우리는 void가 가리키고 있는 데이터의 형태를 알고 있습니다. 우리는 똑똑하니까요(?). 그래서 우리는 *b가 무엇이냐 라고 질문할때 100이라고 대답할 수 있습니다. 우리는 똑똑하기 때문이죠.
하지만 단순히 주소값만!알고 있는 우리 void형은 그 형태가 int형이든 char 형이든 구조체든 문자열을 가리키고 있는 포인터이든 상관없이 단순히 주소값만이요. 그러니 void포인터는 자료형이 무엇이든 간에 주소값만 바라봅니다.
주소만 갖으면 되기 때문에 포인터의 크기(4바이트)만 갖고 있고, 포인터 연산조차 할 수 없습니다.
정말 읽을 수 없는 지 한번 코드로 살펴봅시다.
#include <stdio.h> int main() { int a = 10; void *b = &a; printf("%d\n", *b); }
실행시킬 수 조차없이 빨간줄로
Error:Expression must be a pointer to a complete object type
라는 에러를 보게 됩니다.
완전한 형태의 포인터로 바뀌어야한다 라고요.
우리는 컴퓨터에게 "너가 가리키고 있는 데이터 자료형은 int형이야" 라고 명확히 알려주어야합니다. "그러니까 넌 묻지도 따지지도 말고 4바이트만 읽으면 돼!" 라고요.
어떻게 알려줄까요??
우리는 형변환을 알고 있습니다. 그걸 사용하는 것이죠.
printf("%d\n", *(int*)b);
이렇게 하면 void*는 int형을 읽을 수 있는 int*로 변환되게 됩니다.
정말 빨간 줄 없이 int형 데이터를 읽을 수 있는 지 코드로 볼까요?
#include <stdio.h> int main() { int a = 10; void *b = &a; printf("%d\n", *(int*)b); }
빨간 밑줄은 없어졌군요~
실행도 정상적으로 되는 것을 확인할 수 있고, 10을 정확히 읽는 것도 확인할 수 있습니다.
char형은 어떻게 변환할까요? 그것도 간단합니다. 바로 char*로만 바꾸어주면 됩니다.
#include <stdio.h> int main() { char a= 'c'; void *b = &a; printf("%c\n", *(char*)b); }
네, 'c'라는 문자를 제대로 읽을 수 있군요.
문자열 역시 다르지 않습니다.
#include <stdio.h> int main() { char *str= "문자열"; void *b = str; printf("%s\n", (char*)b); }
str자체가 문자열을 가리키고 있는 포인터이기 때문에 str변수 앞에 &(amp)를 붙여주지 않습니다. 이해하죠?
문자열도 잘 읽어오는군요.
이렇게 void포인터는 만능입니다. 어떤 자료형이건 바로 참조할 수있죠. 알맞은 자료형으로만 변경한다면 말이죠.
우리는 void포인터를 동적할당할때 유용하게 사용합니다. 동적할당에 사용하는 malloc과 같은 함수들이 void*로 반환하기 때문입니다.
malloc은 특정한 size의 크기로 메모리를 할당하고나서 우리들에게 알맞게 변환해서 써라 라는 의미로 void*를 내뱉게 됩니다.
어차피 나중에 배울 malloc함수의 원형 한번 볼까요?
void *malloc(size_t size)
앞서 말한대로 void*를 토하고 있습니다. 너네가 맘대로 바꾸라고 말이죠.
한번 보세요. 아~ 이런 변태같은 함수도 있구나~ 라고 기억하시기 바랍니다.
이것으로 void포인터에 대해 설명해보았습니다. 감사합니다.