C에서는 괄호 없이 함수를 적어줌으로써 함수의 주소 얻을 수 있다.
그리고 그 주소를 함수 포인터와 void 포인터에 넣을 수 있다.
하지만 int 같은 형을 가진 포인터들에 주소를 넣어주려 하면, 에러를 뱉어낸다.
기본적으로 주소에서 몇 바이트만큼 읽어올 것인지와 포인터에 대한 연산이 포인터의 형에 따라 달라지기 때문에 당연하다고 볼 수도 있다.
예를 들어서 int형 포인터는 +1 하면 4바이트씩 더해져서 읽어진다.
void 포인터는 일반적으로 포인터 타입 캐스팅한 뒤에 사용된다.
함수 포인터와 void 포인터 둘다 함수의 주소를 넣어줄 수는 있지만 함수를 실행시키는 것은 함수 포인터만 가능하다.
내부적으로는 둘다 차이가 없는지 궁금해서 gdb로 뜯어보겠다.
gcc -g -o C C.c로 컴파일해주고 gdb로 까 봤다.
main+12에 break를 걸어서 천천히 확인해보겠다.
fp와 ptr둘다 각각 [rbp - 0x10], [rbp - 8]에 위치해있다.
명령을 조금 더 건너뛰고 ptr과 fp에 뭐가 들어있는지 확인해보겠다.
조금 편하게 디버깅하려고 -g 옵션을 주고 gdb로 까서 쉽게 확인할 수 있었다.
실질적으로 [rbp - 8]와 [rbp - 0x10], 즉 ptr, fp 둘 다 똑같이 함수의 주소가 들어간다.
gdb가 여기서 두 가지를 구분해줄 수 있는 이유는 디버깅 정보를 포함해서 컴파일을 했기 때문이지 실질적으로 값이 다른 것은 아니라고 한다.
좀 더 자세한 설명은 아래에 더 잘 나와있다.
https://stackoverflow.com/questions/6132922/given-a-pointer-how-does-gdb-get-its-type
값 자체는 같다는 것을 확인할 수 있다.
나머지 부분은 add 호출하거나 출력하는 부분이니 넘어가겠다.
결론적으로 포인터는 내부적으로 주소로 저장되고, 포인터에 대한 처리는 컴파일러가 알아서 해주는 것 같다.
그냥 삽질했지만, gdb에 익숙해지는데 도움이 된 거 같다.
'프로그래밍 > C' 카테고리의 다른 글
execve() argv 포인터 배열 확인 (0) | 2022.05.24 |
---|---|
C 배열 포인터 array VS &array 차이, 디버깅을 통한 확인 (0) | 2022.05.22 |
size_t, pid_t,ssize_t... (0) | 2022.05.03 |
open, read 시스템콜을 이용한 파일 입출력 (0) | 2022.05.03 |
scanf, gets, fgets 차이 (0) | 2022.04.01 |