Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

주요 콘텐츠로 건너뛰기

이 브라우저는 더 이상 지원되지 않습니다.

최신 기능, 보안 업데이트, 기술 지원을 이용하려면 Microsoft Edge로 업그레이드하세요.

형식 캐스팅 변환

  • 아티클
  • 09/26/2022
  • 읽는 데 3분 걸림

이 문서의 내용

형식 캐스팅을 사용하여 명시적으로 형식을 변환할 수 있습니다.

구문

cast-expression:
    단항 식
    (type-name)cast-expression

type-name:
    specifier-qualifier-listabstract-declaratoropt

type-name은 형식이고 cast-expression은 해당 형식으로 변환할 값입니다. 형식 캐스팅을 사용하는 식은 l-value가 아닙니다. cast-expression은 type-name 형식의 변수에 할당된 것처럼 변환됩니다. 할당에 대한 변환 규칙(할당 변환에 개괄되어 있음)은 형식 캐스팅에도 적용됩니다. 다음 표에서는 임의의 형식으로 캐스팅될 수 있는 형식을 보여 줍니다.

올바른 형식 캐스팅

대상 형식잠재적 소스
정수 계열 형식 표 임의의 정수 형식 또는 부동 소수점 형식이나 개체에 대한 포인터
부동 소수점 산술 형식
개체에 대한 포인터 또는 (void*) 임의의 정수 형식, (void*), 개체에 대한 포인터 또는 함수 포인터
함수 포인터 임의의 정수 계열 형식, 개체에 대한 포인터 또는 함수 포인터
구조체, 공용 구조체 또는 배열 없음
void 형식 모든 형식

모든 식별자를 void 형식으로 캐스팅할 수 있습니다. 그러나 형식 캐스트 식에 지정된 형식이 void가 아닌 경우 해당 형식으로 캐스팅되는 식별자가 void 식이 될 수 없습니다. 모든 식을 void로 캐스팅할 수 있지만 void 형식의 식은 다른 형식으로 캐스팅할 수 없습니다. 예를 들어, void 반환 형식이 포함된 함수의 반환 형식을 다른 형식으로 캐스팅할 수 없습니다.

void* 식에는 void 형식이 아니라 void 에 대한 형식 포인터가 있습니다. 개체가 void 형식으로 캐스팅되면 결과 식을 어떠한 항목에도 할당할 수 없습니다. 마찬가지로, 형식 캐스팅 개체가 허용 가능한 l-value가 아니므로 형식 캐스팅 개체에 어떠한 항목도 할당할 수 없습니다.

Microsoft 전용

형식 캐스팅은 식별자의 크기가 변경되지 않는 한 l-value 식이 될 수 있습니다. l-value 식에 대한 자세한 내용은 L-Value 및 R-Value 식을 참조하세요.

Microsoft 전용 종료

캐스팅을 사용하여 식을 void 형식으로 변환할 수 있지만 결과 식은 값이 필요하지 않은 위치에서만 사용할 수 있습니다. void*로 변환되었다가 다시 원래 형식으로 변환된 개체 포인터는 해당 원래 값으로 되돌려집니다.

참조

형식 변환

 드디어 200번째 글입니다. void형 포인터에 대해서 배워봅시다. 보통 우리는 다음과 같이 썼을 거에요.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 이것은 무엇을 의미할까요? 일단 p에 15를 넣습니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 p는 메모리에 어딘가에 할당이 되어 있을 겁니다. 그리고 이 p의 주솟값을 a가 들고 있습니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 예를 들어 p의 주소가 0x80이라면 a는 0x80을 들고 있는 것입니다. 다음에 (*a)++이 있는데요. 이는 (*a) = (*a) + 1을 의미합니다. a를 역참조하면 p가 되므로, 결국 p에 1을 증가시키라는 것과 같습니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 최종적으로는 p = 16이 될 거에요. a는 int형 자료형을 가르켰어요. void형 포인터는 이와 다르게, 주솟값을 저장하고 있기는 한데, 가리키는 자료형을 모르는 pointer를 의미합니다.


 아래 예제를 봅시다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 int형 변수인 p와 double형 변수인 q가 있습니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 6번째 줄에 void형 포인터 a가 선언되었습니다. a에는 p의 주솟값이 들어가는데요. 이 때, a는 p의 주소값을 들고 있어요. 가리키는 대상은 일단 int형입니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 7번째 줄에는 double형 변수인 q의 주소를 들고 있어요. 즉, a는 q를 가리키고 있어요. 그러면, 이 a는 서로 다른 데이터 타입을 가리킬 수 있다는 이야기가 됩니다. 만약에, a를 void형 포인터가 아닌 int를 가리키는 포인터로 선언을 했다고 해 봅시다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 그러면, double *를 int *로 assign 할 수 없다는 오류가 뜰 거에요. 그러면, void형 pointer는 모든 data type을 가리킬 수 있는 만능이라고 생각하면 좋을까요? 일단 넵. generic pointer라고도 이야기를 한다는 것 정도 챙기시면 좋겠습니다.


 그러면, 역참조가 가능할까요? C 표준에서는 이를 허용하지 않습니다. 그렇지만, 실제로 가능한 지는, 컴파일러마다 다를 수 있어요. 인터넷 컴파일러인 wandbox에서는 허용하지 않습니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 이는 void형 포인터가 어떤 자료형을 가리키는지 모르기 때문입니다. int형? double형? 아니면 long long형? char형? 어떤 것을 가리키는 지 알 수 없어요. 따라서, 강제 형변환을 해 주어야 합니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 8번째 줄을 하나 하나 해석해 봅시다. a는 일단 void형 pointer였습니다. (double *)a는, a를 double형 포인터로 강제 형 변환을 했다는 의미입니다. 그러면 이것을 역참조 하면, 실 데이터 q로 접근할 것인데, q가 double형이고, pointer는 double형을 가리키는 것으로 형변환이 되었으니, 제대로 접근할 수 있겠네요.

 따라서, 컴파일 오류도 뜨지 않고 2.0000000000 이라는 값이 출력됩니다. malloc 함수의 리턴 값이 void *형인데, 우리는 이를 (int *)이라던지, (char *)형으로 casting을 했어요. 그런 것과 같다고 보시면 되겠습니다.


 void 형 포인터는, 모든 자료형을 가리킬 수 있고, 역참조를 할 때 적절히 형변환을 하면 된다. 이것을 잘 기억하시면 왜 qsort의 1번째 인자가 void *인지 알 수 있습니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 만약에, void형 포인터를 인자로 받지 않았다고 생각해 봅시다. 그러면, int형을 비교할 때, double형을 비교할 때, 사용자 구조체 형을 정렬할 때, 각각 따로 함수를 만들어야 했을 거에요. 그런데, 우리는 2번째 인자와 3번째 인자가 왜 필요한지 의문이 드실 겁니다. 이는 간단합니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 void형 pointer를 받았습니다. 그러니, qsort 내부의 입장에서는 한 원소마다 몇 byte의 크기를 가지는지, 몇 개나 있는지 모릅니다. 이 둘을 명시를 해 준다면, 다음 원소를 가기 위해서, 주솟값을 size byte만큼 증가시키면 된다는 것을 알 수 있기 때문입니다. 일례로, size가 10이고, a가 현재 원소를 가리켰는데, 다음 원소를 가리키게 하려면 아래와 같이 작성하면 될 거에요.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 char형의 크기가 1byte라면, 이렇게 작성해도 무난합니다. 그 다음에 compare가 있습니다. 이것은 void형 포인터를 2개 받는 함수의 포인터인데요.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 base가 void형 포인터였다. 어느 형을 가리키는 지 몰랐다. 그렇다면 비교체 함수를 호출할 때 Key 2개를 가지고 비교할 거에요. 그런데 그 키가 어떤 형인지 모릅니다.

Void 포인터 형변환 - Void pointeo hyeongbyeonhwan

 그런가요? 노란색 2개를 비교했을 때, 어떤 형을 가리키는지 모르는 상황입니다. 그러니 void형 포인터로 인자를 넘겨 받을 겁니다. 그러면 사용자가 compare를 구현할 때 어떻게 하면 되나요? compare 함수 내에서 형변환을 하면 됩니다. 이 부분은 사용자가 재정의를 하는 부분입니다.

 단지 qsort는 내가 정의한 compare를 토대로 key 값 비교를 하면서 정렬을 하는 역할만 할 뿐입니다. 즉, 우리는 double형이던, int형이던, struct moo형이던 compare 함수만 어떻게 잘 정의하면 double형도, int형도, moo형도 sort를 할 수 있습니다. 오늘 배운 것의 강력함이라고 할 수 있어요. void형 포인터는 generic이다. 이 한 마디만 정리하셔도 좋을 듯 싶네요.