막뇌 2023. 5. 15. 19:21

메모리 주소를 의미하는 포인터변수 앞에 붙은 자료형은 해당 포인터 변수가 어떤 값의 변수를 참조할 것인지를 의미 합니다.

int* pnum; 이 의미하는 것은 pnum이 참조하는 대상의 값이 int 형이라는 것을 의미 하죠.

void 포인터란 가리키는 대상의 자료형이 정해지지 않은 포인터를 의미합니다.

 

void 포인터 사용 예제

#include<stdio.h>

int main(void)
{
    int a = 10; //int variable
    double b = 3.5; //double variable
    void* vp;   //void pointer

    vp = &a;    // assign void pointer to int variable
    printf("a : %d\n", *(int*)vp);

    vp = &b;    // assign void pointer to double varible
    printf("b : %d\n", *(double*)vp);

    return 0;
}

void 포인터는 어떻게 사용하는지 알아보겠습니다.

void* vp

선언은 여느 포인터 변수와 같습니다. 어떤 자료형을 가리키는지를 먼저 적고 포인터 변수임을 알리는 *와 함께 변수명을 작성하면 됩니다.

vp = &a
vp = &b

위처럼 값을 대입할 때도 기존 포인터 변수와 똑같이 작성합니다.

*(int*)vp
*(double*)vp

사용할 떄는 조금 다릅니다.

맨처음 등장하는 * 는 참조하는 대상의 값에 접근 하겠다는 의미입니다.(참조 연산자)

이후에 (double*) 라는 형태가 등장하게 됩니다.

지금 void포인터가 간접참조 연산을 수행하기 위해 주소값을 참조 한 상태이지만 주소값만 저장되었을 뿐입니다.(&a, &b가 저장됨)

알기 쉽게 하기 위해 코드를 조금 고쳐 보았습니다.

#include<stdio.h>

int main(void)
{
    int a = 10; //int variable
    double b = 3.5; //double variable
    void* vp;   //void pointer

    vp = &a;    // assign void pointer to int variable
    printf("%p\n", vp);	// 추가된 코드
    printf("a : %d\n", *(int*)(vp));

    vp = &b;    // assign void pointer to double varible
    printf("%p\n", vp);	//추가된 코드
    printf("b : %lf\n", *(double*)(vp));

    return 0;
}

주소값만 저장되었을 뿐인 void* 형태에서 *(참조연산자)를 사용.

'값을 가져와라' 라고 명령하면 컴퓨터는 실행을 못합니다.

왜냐하면 그 값이 어떤 속성인지 몰라서 그런겁니다.

void 포인터를 알면 우리는 차량이나 오토바이가 있는 주소까지 도달할 수 있습니다.

말 그대로 주소까지 갈 수는 있는데 왜 주소까지 가나요?

결국은 사용하기 위해서 주소로 가는것 아닌가요?

주소로 가긴 갔는데 이게 뭐하는 기계이고, 운전은 어떻게 하는것이고, 시동은 어떻게 걸어야 하는지 알아야 오토바이를 타고 전국일주를 가든 차를 타고 차박을 가든 할것 아닌가요?

그 속성을 알려주는것이 바로 void포인터의 명시적 형변환 입니다.

자료를 활용하려면 자료의 형태(속성)를 알아야 한다.

 

(int*)vp
(double*)vp

지금까지 설명한 것이 코드에서 위와 같은 형태로 나타납니다. 마치 자료형 끼리 (int) (float)형변환을 한것 같네요 맞습니다. void 포인터를 각각 int* double* 형으로 형변환 한 것입니다.

포인터 변수이기 때문에 정수 연산도 가능합니다.

(int*)vp + 1 과 같이 코드를 작성하면 포인터의 정수연산과 동일하게 작동합니다.(다음 4바이트 메모리가 참조됨)

(double*)vp + 1을 하면 다음 8바이트 메모리가 참조 되겠지요?

 

형변환을 하지 않는 경우도 있습니다.

포인터 변수를 선언하면서 대입(assign)연산을 할 때인데요. void 포인터를 다른 포인터에 대입 하는 경우에는 형변환을 하지 않아도 됩니다.

int* pnum = vp;

예제 코드 중간에 위와 같은 코드를 넣을 경우 형변환을 하지 않고 사용이 가능합니다.

그래도 형변환을 항상 해주는게 좋습니다. 해야만 하는 경우가 있고 안해도 되는 경우가 함께 있을 경우 무조건 해주는게 좋습니다. 사고 방지를 위해서죠. 아래는 명시적 형변환을 해 주고 완성한 코드입니다.

int* pnum = (int *) vp;