int imsi[]={7, 4, 9}; void *voidp; voidp=imsi; for(i=0;i<sizeof(INT) / sizeof(int); i++) (1) printf("%d\n", *((int *)voidp)++); // * ( ( int *) voidp ) ++ (2) printf("%d\n", *(int *)voidp++); // * ( int * ) voidp ++ [출력결과] (1) 7 4 9 (2) 7 (Segmentation Fault) memory dumped |
두번째 수행문은 문제를 발생시킨다.
위의 (1)번은 ((int *)voidp)가 하나의 덩어리가 되었으므로 *imsi++와 같은 의미로 사용될 수 있다는 것을 알 수 있다.
*((int *)voidp)++ 수식을 하나씩 정리해보자.
- voidp
void형 포인터 변수이다. 어떠한 주소 값도 들어갈 수 있으며 단지 가리키는 곳에서 몇 바이트 읽어올지 알 수 없으므로 캐스트 연산자를 이용하는 것이다.
- (int *)voidp
voidp에 있는 값을 int형 주소값으로 변환한다. 이 말은 voidp에서 나중에 값을 꺼내올때 voidp가 가리키는 곳에서부터 4바이트를 읽어 온다는 말과 같다.
- (int *)voidp)++
void에 있는 값을 int형 주소 값으로 변환하고 ++를 이용하여 int형만큼 분기한다. 그런데 ++는 후치 연산이기 때문에 다음에 이를 적용받게 된다.
- *(int *)voidp)++
++에 걸리는 대상체가 괄호 전체가 되므로 위의 수식에서 ++의 대상체는 (int *)voidp가 된다. voidp에 들어있는 값을 int형을 가리키는 주소 값으로 변환했기 때문에 ++ 수식을 사용할 수 있는 것이다. ++에 걸리는 대상체가 "int *"라는 것을 다음 프로그램으로 확인할 수 있다.
main() { int imsi[3] = {6, 3, 7}; int *imsip; void *voidp; imsip = imsi; voidp = imsip; printf("1. %d\n", * ( ( double * ) voidp) ++); printf("2. %d\n", * (int *)voidp); } [출력결과] 1. 6 2. 7 |
*((double *)voidp)++에 의해서 증가되는 주소 값은 8바이트가 된다. ++의 대상체는 (double *)voidp이기 때문이다. 8바이트가 움직인 상태에서 *(int *)voidp를 출력해보면 무엇이 나오겠는가? 당연히 7이라는 값이 나올 것이다.
출처: 다시 체계적으로 배우는 C언어 포인터(정보문화사:정재은 저)