포인터 함수 메모리 그림 질문하겠습니다.

조회수 433회

main 함수에서 포인터를 지정한 후 정의된 다른 함수를 불러옵니다. 그리고 그 함수에 포인터의 주소를 대입하면 메모리 그림에서는 다른 함수를 정의할때 괄호 안에 썼던 예를 들면 int* ptr이런게 실제로 생기는 건가요 아니면 int* ptr 은 그냥 가상의 변수인가요?

  • 함수 포인터를 말씀 하시는 것인가요, 포인터에 대한 물리적인 이해를 물어보시는건가요? 글을 한 10번정도 읽으니까 후자이신 것 같은데... 예. int* ptr 이던 변수든 뭐든 그냥 전부다 가상의 변수입니다. dbwodlf3 2020.10.7 14:33
  • stack 메모리에 대해서 이해하시면 변수에 대해서도 이해하실 수 있으실 것 같습니다. dbwodlf3 2020.10.7 14:34
  • C언어에서는 가장 작은 프로시저 단위가 function 이고. function 에서 사용하는 모든 로컬변수는 stack에 할당됩니다. dbwodlf3 2020.10.7 14:34
  • int* ptr; 하면 스택에 32bit 공간이 생깁니다. (사용 안하면 최적화 중에서 안만들도록 합니다.) dbwodlf3 2020.10.7 14:35

1 답변

  • 코딩해놓은 한줄이 실제로 있는가 가상의 변수인가를 생각하실 필요가 없는게 프로그램 사전에 정의되지 않는 변수명이 없으면 동작이 안되는것만 생각하시면 편하실거라 생각되는데 :(

    솔직히 말해서 질문 내용에 있어서 포인터 가 언급되는건 해당 질문 내용에 있어 무관한 내용인거 같고 예시가 없어서 처음에 질문글 보고 햇갈렸었네요..

    결론부터 말씀드리면 해당 변수가 들어갈 공간은 해당 함수에 진입할때 같이 생성됩니다.

    #include <stdio.h>
    #include <stdlib.h>
    
    void test(int *abc)
    {
            printf("%d\n", *abc);
    }
    
    int main()
    {
            int *ptr;
            ptr = (int *)malloc(sizeof(int));
            *ptr = 123;
            test(ptr);
            return 0;
    }
    

    위와 같은 코드를 디버깅 하여 확인 해보겠습니다

    gdb-peda$ disas test
    Dump of assembler code for function test:
       0x000000000000068a <+0>:     push   rbp
       0x000000000000068b <+1>:     mov    rbp,rsp
       0x000000000000068e <+4>:     sub    rsp,0x10
       0x0000000000000692 <+8>:     mov    QWORD PTR [rbp-0x8],rdi
    ...
       0x00000000000006af <+37>:    nop
       0x00000000000006b0 <+38>:    leave
       0x00000000000006b1 <+39>:    ret
    End of assembler dump.
    
    gdb-peda$ disas main
    Dump of assembler code for function main:
       0x00000000000006b2 <+0>:     push   rbp
       0x00000000000006b3 <+1>:     mov    rbp,rsp
       0x00000000000006b6 <+4>:     sub    rsp,0x10
       0x00000000000006ba <+8>:     mov    edi,0x4
    ...
       0x00000000000006d2 <+32>:    mov    rax,QWORD PTR [rbp-0x8]
       0x00000000000006d6 <+36>:    mov    rdi,rax
       0x00000000000006d9 <+39>:    call   0x68a <test>
       0x00000000000006de <+44>:    mov    eax,0x0
       0x00000000000006e3 <+49>:    leave
       0x00000000000006e4 <+50>:    ret
    End of assembler dump.
    

    어셈블리코드를 참고하시면 다른 함수로 들어갈때

     - main func
       mov    rax,QWORD PTR [rbp-0x8]
       mov    rdi,rax
       call   test
    
     - test func
       push   rbp
       mov    rbp, rsp
       sub    rsp, 0x10
       mov    QWORD PTR [rbp-0x8],rdi
    

    기존에 돌아갈 주소를 스택에 쌓아두고 새롭게 스택을 구축합니다 그리고 x64 linux calling convention 에 따라 rdi 에 해당 변수를 넣고 함수를 호출하죠

    rdi 값은 동일하고 새로운 함수에 왔으니 새로운 스택을 가지고 sub rsp 0x10 을 통하여 새로운 변수를 넣을 공간을 만든 이후에 rdi 값을 넣어줍니다.

    그리고 함수가 종료시에는 해당 함수에서 사용했던 스택공간을 다 비우고 원래 함수가 호출됬던 시점으로 돌아가게 됩니다.

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)