01 개념적 구조
프로세스에는 크게 text(code), data, heap, stack으로 영역이 나누어진다. 다음은 가상 메모리의 주소 공간을 나타낸 그림이다.
02 C프로그램으로 보는 프로세스 구조① (function pointer)
#include <stdio.h>
int a = 10;
int fun1(int arg1) {
printf("fun1에서의 arg1 = %d\n", arg1);
}
int main() {
int *pa;
int (*func_ptr)(int);
pa = &a;
printf("a의 주소를 가리키는 포인터 pa = %p\n", pa);
printf("포인터 pa안에 들어있는 값 *pa = %d\n", *pa);
fun1(3);
func_ptr = func1;
func_ptr(5);
printf("종료\n");
}
<결과>
func_ptr = func1; 에서 함수의 이름이 시스템의 입장에서 해당 함수의 주소를 의미한다는 것을 알 수 있다.
03 C 프로그램으로 보는 프로세스 구조② (address printing)
#include <stdio.h>
#include <stdlib.h>
int glob1, glob2;
int func2() {
int f2_local1, f2_local2;
printf("func2함수 내 지역변수의 주소: \n\t%p, \n\t%p\n", &f2_local1, &f2_local2);
}
int func1() {
int f1_local1, f1_local2;
printf("func1함수 내 지역변수의 주소: \n\t%p, \n\t%p\n", &f1_local1, &f1_local2);
func2();
}
int main(){
int m_local1, m_local2;
int *dynamic_addr;
printf("main함수 내 지역변수의 주소 : \n\t%p, \n\t%p\n", &m_local1, &m_local2);
func1();
dynamic_addr = malloc(16);
printf("동적할당 변수의 주소 : \n\t%p\n", dynamic_addr);
printf("전역변수의 주소 : \n\t%p, \n\t%p\n", &glob1, &glob2);
printf("함수들의 주소 : \n\t%p, \n\t%p, \n\t%p\n", main, func1, func2);
return 0;
}
<결과>
04 정리
프로세스는 text, data, stack, heap으로 4개의 segment로 구성되어 있다.
text 영역에는 어셈블리어의 프로그램 코드가 들어가며, 프로그램 코드 실행 순서에 따라 주소가 커진다.
data 영역에는 전역 변수가 들어가고, 초기화 된 데이터(data)와 초기화되지 않은 데이터(bss)를 구분해서 관리한다.
stack 영역에는 지역 변수, 인자(argument), 리턴주소(return address)가 들어간다. 함수가 실행됨에 따라 높은 주소부터 낮은 주소로 쌓인다.
heap 영역은 malloc(), calloc() 등과 같은 동적으로 할당된 것들이 저장되고, 낮은 주소에서 높은 주소로 할당된다.