C언어 포인터는 왜 타입별로 구분되어 있는가?
#include<stdio.h> int main() { int a = 300000000; // int형 변수에 300000000를 저장 double b = 3.0; // double형 변수에 3.0 저장 int * c = &a; // c는 a의 주소를 저장 double * d = &b; // d는 b의 주소를 저장 int e = a + *c; // a + (c가 가리키는 주소에 저장된 값) double f = b + *d; // b + (d가 가리키는 주소에 저장된 값) }
위 코드에서는 int형 변수a에 3_0000_0000을 저장하고, double형 변수 b에는 3.0을 저장합니다.
그리고, int 포인터형 변수 c에는 a의 주소를 저장하고, double 포인터형 변수 d에는 b의 주소를 저장합니다.
마지막으로, int형 변수 e에는 a와 c가 가리키는 주소에 저장된 값을 더한 값,
double 형 변수 f에는 b와 d가 가리키는 주소에 저장된 값을 더해서 넣어줍니다.
한 바이트에 할당된 주소가 32비트일 때, 메모리를 도식화하면 아래와 같은 그림이 됩니다.
한 칸이 한 바이트를 의미합니다.
따라서 int형 변수인 a는 4개의 칸으로, double 형 변수인 b는 8개의 칸으로, 포인터 변수인 d는 4칸으로 표현하였습니다.
한 바이트씩 한 줄로 나열해야되지만, 편의상 아래와 같이 도식화하였습니다.

아 그래서 포인터가 왜 타입별로 구분되어 있는건데~!
만약 int형 포인터가 가리키는 주소에서 값을 가져온다고 생각해봅시다.
그럼, int형은 4 바이트이기 때문에, int형 포인터가 가리키는 주소에서 4바이트 가져오면 될 것입니다.
반면, double형 포인터가 가리키는 주소에서는 4 바이트가 아닌 8바이트를 가져와야합니다.
즉, int형 포인터든, double 형 포인터든 주소를 저장하기 때문에 크기는 동일합니다만,
해당 주소에서 몇 바이트를 가져올 것이냐가 전혀 다릅니다.
따라서 컴파일 되고, 기계어로 번역될 때 다른 명령어로 번역이 되는거죠.
어셈블리어(Assembly language) 분석
아래는 위 코드를 디어셈블러로 기계어를 어셈블리어로 변환한 코드입니다.
int main() { /* main() 함수의 실행을 준비하는 prologue */ int a = 300000000; // int형 변수에 300000000를 저장 00711718 mov dword ptr [a],11E1A300h double b = 3.0; // double형 변수에 3.0 저장 0071171F movsd xmm0,mmword ptr [__real@4008000000000000 (0717B30h)] 00711727 movsd mmword ptr [b],xmm0 int * c = &a; // c는 a의 주소를 저장 0071172C lea eax,[a] 0071172F mov dword ptr [c],eax double * d = &b; // d는 b의 주소를 저장 00711732 lea eax,[b] 00711735 mov dword ptr [d],eax // 핵심! int e = a + *c; // a + (c가 가리키는 주소에 저장된 값) 00711738 mov eax,dword ptr [c] 0071173B mov ecx,dword ptr [a] 0071173E add ecx,dword ptr [eax] 00711740 mov dword ptr [e],ecx double f = b + *d; // b + (d가 가리키는 주소에 저장된 값) 00711743 mov eax,dword ptr [d] 00711746 movsd xmm0,mmword ptr [b] 0071174B addsd xmm0,mmword ptr [eax] 0071174F movsd mmword ptr [f],xmm0 /* main() 함수의 실행을 종료하기 위한 epilogue */ }
핵심 주석 아래에 있는 코드만 보시면 됩니다.
a + * c를 할 때는, c의 주소에서 4 바이트를 가져와서 eax 레지스터에 저장하고(a의 주소),
a의 주소에서 4바이트를 가져와서 ecx에 저장합니다(a의 값).
그리고, eax 레지스터에 있는 a의 주소에서 4바이트를 가져와서(a의 값) ecx에 있는 값과 더한 다음 e의 주소에 저장해줍니다.
설명이 어렵게 느껴지실 수 있습니다.
간단하게만 보시면, int형 포인터 변수인 c와 double형 포인터 변수에 저장된 주소에서 값을 가져올 때, 명령어가 전혀 다른 것에만 주목하시면 됩니다.
포인터 변수에 저장된 주소로부터 몇 바이트 불러올 건지가 다르기 때문에, 서로 다른 명령어로 변역되는 것입니다.
따라서, 포인터가 동일한 크기의 주소를 저장함에도 타입별로 구분되어 있는 것이죠.
'C\C++' 카테고리의 다른 글
C++ (Call By Value, Call By Reference) (0) | 2022.08.19 |
---|