상세 컨텐츠

본문 제목

[C] 포인터(1)

개발공부/C

by 임우찬 2019. 9. 11. 11:17

본문

 

1. 프로그램과 프로세스

- 프로그램과 프로세스의 차이는 매우 간단하다. 프로그램은 실행파일이다.

파일 시스템 상에 존재하는 실행 파일이 프로그램이다.

(확장자가 .exe인 파일)

이 실행파일을 실행하였을 때 메인메모리상에 이 프로그램에 메모리를 할당해준다.

메모리상에 올라가 CPU를 할당받을 수 있는 상태의 프로그램을 프로세스라고 한다.


2. 빌드

우리는 비주얼 스튜디오에서 C로 코드를 짜고 컨트롤+f5를 하곤 한다.

이 컨트롤+f5는 무엇을 하는 것일까?

빌드 과정이다.

- 우리가 ctrl+f5를 하는 것은 "빌드"라고 하는 것이다.

이 빌드는 컴파일과 링크의 과정으로 이루어져 있다.

우리가 소스코드를 작성해서 실행을 했는데 소스코드에 printf()라는 함수가 있다고 가정하자. 그렇다면 컴퓨터는 과연 printf함수를 p.r.i.n.t.f와 같이 스펠링으로 읽을까? 그렇지 않다. 컴퓨터는 0101010101같은 기계어밖에 읽을 수 없다.

따라서 우리가 짠 소스코드들을 기계어로 바꾸어 주는 과정이 필요하다. 이 과정을 우리는 "컴파일"이라고 한다.

이후 한 프로젝트에는 main함수는 하나밖에 있을 수 없지만, 소스코드는 여러 개를 가질 수 있다. 만약 소스코드가 여러 개인 c 프로그램이라면, 한 프로젝트에서 그 여러 개의 소스코드를 합쳐주는 과정을 필요로 한다. 이 과정을 우리는 "링크"라고 한다.

그리고 이 컴파일 과정과 링크과정을 합한 것을 빌드(ctrl+f5)라고 부르고 쓰는 것이다.

우리가 소스코드를 작성해서 궁극적으로 만들고자 하는 것은 응용프로그램이다. 이는 밑의 사진을 보면 알 수 있다.

처음 프로젝트명을 Project2로 시작하여 Project2.exe라는 파일이 생성되었다.

오른쪽의 솔루션부분 밑을 보면, 우리가 프로젝트를 만들 때 사용하였 던 프로젝트 이름을 볼 수 있다. 그리고, 소스코드를 대충 작성한 뒤 실행을 하면, 콘솔창에 폴더경로/.../Project2.exe

이를 보면 알 수 있지만, 우리가 소스코드를 작성하여 궁극적으로 만들고자 하는 것은 확장자명이 .exe인 응용프로그램이다.

- 위에서 프로그램과 프로세스에 대해서 잠깐 설명했었는데, 결국 우리가 짠 소스코드도 결국 응용 "프로그램"이 된 것이고 우리는 이를 컨트롤 f5를 통해 프로세스로 만들어, 메인 메모리상에 올려놓아 CPU를 할당받을 수 있도록 한 것이다.

* (CPU는 중앙처리장치의 약자로, 컴퓨터의 정중앙에서 모든 데이터를 처리하는 장치이다. 간단하게 프로그램을 실행할 수 있도록 도와주는 정도로만 생각해두자.)


3. 메인메모리(RAM)

우리가 컴퓨터를 켜고 여러 작업들을 한다고 가정하자. 카카오톡과 크롬을 밑에 깔아두고 비주얼 스튜디오를 켜 코딩을 하고있다고 생각하자.(다른 기본적인 프로세스들은 하나도 실행되고 있지 않다고 가정하자.) 그럼 우리는 지금 카카오톡과 크롬과 비주얼 스튜디오를 동시에 실행하고 있다고 볼 수 있다.

하지만, 이것은 동시에 실행되는 것이 아니다.

카카오톡과 크롬과 비주얼스튜디오 모두 프로그램이므로, 현재 메인 메모리상에 올라가있을 것이다. 이 메인 메모리상의 프로세스들을 아주 빠른 속도로 카카오톡을 실행하고 크롬을 실행하고 비주얼스튜디오를 실행하고를 반복하여 동시에 실행되고 있는 것 처럼 보이는 것이다.

메인 메모리상의 프로그램들을 CPU로 가져와 연산하는것이다.

(CPU에 관한 내용은 이 곳에 있다.)

https://dlaxodud2388.blog.me/221613076571

이 이야기는 조금 뒤에 다시 이야기하겠다.


4. 주소공간

프로그램이 메인 메모리 상에 올려질 때, 운영체제는 메인메모리 공간의 일부를 그 프로그램에게 할당해준다.

이 프로그램이 할당받은 공간은 주소공간으로 이루어져 있다.

그런데 이 주소공간도 큰 주소부터 작은 주소순서로 4가지 공간으로 나누어져 있다.

위 사진과 같이 주소공간은 4가지 공간으로 나누어져 있다.

- CODE 영역 : 코드 그 자체를 구성하는 메모리 영역이고, 기계어로 제어가 가능한 메모리 영역이다.

- DATA 영역 : 전역변수, static변수, 배열, 구조체 등 프로그램이 종료될 때 데이터가 사라지는 것들로 이루어져 있는 영역이다.

- HIP 영역 : 동적 메모리 할당과 관련이 있다. 포인터에서는 설명하지 않겠다.

- STACK 영역(지역변수, 매개변수 등 특정 스코프를 벗어나면 데이터가 사라지는 것들로 이루어져 있는 영역이다.

따라서 만약,

#include<stdio.h>
int a = 1;
main(){
int b = 2;
double c = 3.0;
}

 

과 같은 코드가 있다면,

프로그램이 실행됨과 동시에 DATA 영역에 전역변수 a가 할당이 되는 것이고,

메인함수에 들어가서 지역변수 b와c가 STACK 영역의 지역변수로 각각 주소값을 가지는 것이다. b변수는 int형이므로, stack영역에서 4바이트만큼의 주소를 가질테고, c변수는 double형이므로 stack영역에서 8바이트만큼의 주소를 가질 것이다.

그렇다면, 이 때 각각의 변수들에게 주소를 할당해주는 역할은 누가 하는 것일까?

이 역할또한 컴파일러가 해준다. 컴파일러는 소스코드도 기계어로 바꿔주며 각각의 변수들도 주소공간의 올바른 영역에 주소값을 무작위로 할당해 주는 것이다.

그럼 왜 굳이 주소공간에 변수들을 저장해야했을까? 그냥 주소공간 없이 영역별로 아무데나 넣으면 안되는 것이였을까?

안된다. 위의 3. 메인메모리 내용에서 말했던 것 처럼, 프로그램이 메모리 상에 올라간 뒤, 이 프로그램들은 동시에 실행되는 것처럼 보이기 위해 CPU상에 올라가서 CPU를 아주 짧은 시간동안 사용할 수 있다.

만약 변수에 주소공간을 할당하지 않아버렸다는 가정하에 예시 코드를 들겠다.

(실제로 그럴일은없다)

#include<stdio.h>
main(){
int a = 1;
int b = 2;
int c = a+b;
printf("%d",&c);
}

만약 다음과 같은 코드를 작성하고 컨트롤 f5를 통해 프로그램을 실행했다고 가정하자. 그런데 많은 프로세스들이 동시에 실행되는 와중에 이 c로 짠 코드도 실행해야 하는데, 그 도중에 a값과 b값을 받아오기만 하고 cpu할당시간이 끝났다고 가정하자. 그렇게 된다면 지금까지 한 작업들을 다시 메인 메모리 상으로 내려야 한다.

근데 지금 받아왔던 변수들을 어디에서 받아왔는지 모른다. 그래서 그냥 아무데나 놓았다. 그랬더니 원래있던 변수 a,b와 다시 가져다놓은 변수 a,b가 한 프로그램에 존재하게 된다. 그러면 다시 cpu를 할당받을때 a,b가 각각 2개씩 있기에 굉장히 치명적인 오류가 발생할 것이다.


5. 포인터란?

이렇게 컴파일러가 할당해준 주소공간에서, 주소공간의 주소값을 가리키는 변수를 말한다.

포인터를 이용한다는 것은 쉽게말해 메인메모리 안의 할당된 주소공간 안의 변수의 주소값에 접근하여 여러 작업들을 한다는 것을 의미한다.

'개발공부 > C' 카테고리의 다른 글

[C] 동적 메모리 할당  (0) 2019.09.11
[C] 포인터(2)  (0) 2019.09.11

관련글 더보기

댓글 영역