저장공간 Register, Stack, Heap, Data
컴퓨터에는 CPU, RAM, HDD가 있다고 했다. 여기서 기억장치는 RAM과 HDD가 있었다. 그리고 추가로 CPU에도 Register(리지스터)라는 저장 공간이 존재한다.(그러나 이 메모리는 매우 소량의 메모리로 직접 쓰는 일은 거의 없다)
메모리는 RAM에서는 3가지를 쓸 수 있다. RAM의 3가지 저장 공간은 Stack(스택), Heap(힙), Data(데이터)다. 여기서 스택과 데이터는 변수선언으로 메모리를 확보한다. Heap(힙)은 그와 다르게 동적할당이다. 이 때 스택의 메모리를 사용하려면, auto가 필요하다. 동적할당은 전에 배웠듯이 malloc()를 사용하고, 데이터는 static다. CPU에 달린 레지스터를 써먹는 것도 register가 필요하다.
Storage class(스토리지 클래스)
사실 int nData와 같이 변수선언을 할 때, 스택메모리를 확보할 때는, 앞에 auto가 붙여야 된다. (보통은 auto인 경우는 생략한다) 변수에는 ‘자료형 이름 = 초깃값;’ 과 같이 썼는데, 맨 앞에 기억부류를 표시하는 것이 맞다. 이 기억부류는 위에 배운 auto, malloc(), static, register로 표시할 수 있는데, 이것을 스토리지 클래스(Storage class)라고 부른다.
지역변수, 전역변수
변수를 변수의 접근성으로 나누자면, 지역변수, 전역변수로 나눌 수 있다. 지역변수는 함수 내부에(스코프{ } 안에) 선언돼서 함수 안에서만 유효한 변수고, 전역변수는 함수 스코프{ } 밖에 선언돼서 모든 함수에서 접근할 수 있는 변수다.
이때 전역변수는 기억부류가 무조건 Data(데이터)가 된다. 데이터 영역에 저장되지 않는 전역변수는 없다는 것을 알아두자. 전역변수는 스코프{ }밖에 벗어나서 어느 함수에서나 따로 변수선언 할 필요 없이 전역변수를 사용할 수 있는데, 이때 지역변수와 전역변수의 이름이 겹치게 되면, 겹칠 때 가장 가까운 스코프{ }안에 있는 변수(지역변수)를 사용한다.
전역변수는 모든 함수에서 사용할 수 있기에, 신중하게 사용해야 되는데, 변수의 이름이 겹치지 않게 g_를 이름 앞에 붙이거나 하는 것이 좋다.
자동변수
지역변수를 자동변수라고 하고(Automatic variable) 사실 이것을 따서 auto라는 스토리지 클래스를 쓴다.(스택 메모리를 사용한다) 자동변수는 지금까지 쓴 대부분의 변수고, auto를 생략해서 쓸 수 있다. (int nData = 10;은 지역변수 + 자동변수다)
함수의 파라미터(매개변수)도 일단 지역변수다. 함수의 매개변수를 따로 바디에서(스코프{ }에서) 정의해주면 에러가 나는데, 이는 함수의 매개변수도 이미 지역변수에 속하기 때문이다. 따라서 매개변수도 지역변수고 자동변수라는 사실을 알아두자.
스코프{ }의 중첩
접근성과 관련된 것이, 스코프{ }인데, 이것을 알려면 식별자(이름)을 알아야 된다. 변수와 함수를 선언할 때, 항상 이름(식별자)를 붙이게 되는데, 이때 식별자를 검색하는 순서가 있다. 대부분 코드작성에 함수가 생성되고, 변수는 함수 안에서 생기기 마련이다.(전역변수가 아니면) 이때의 식별자 검색순서는 이렇다.
첫 번째로 가장 최근에 형성된 스코프{ }에서 검색한다. 두 번째로는 최대로 함수의 바디 안을 검색한다. 이 둘에도 없을 경우, 전역변수를 찾아본다. 여기서 전역변수에서도 못 찾게 되면, 선언되지 않은 식별자라고 결과가 난다.(에러가 난다)
전역변수의 활용
A.c 라는 프로토타입이 있다면 이것이 A.obj 라는 부품이 돼서, A.exe 라는 완제품이(프로그램이)완성된다고 예전에 했었다. 이때, 부품이 여러 개가 붙어서 A.exe 로 합쳐지는 경우가 있다. 그럴 때, A.c 와 B.c 의 프로토타입이 하나의 전역변수를 공유할 수 있을까? 이것을 가능케 하는 것이 'extern'(익스턴)이다. 다른 프로토타입에서 전역변수를 정의하면, 그걸 다른 프로토타입에서 그 전역변수를 선언만 해도 쓸 수 있는 것이다. 이것은 extern int g_nData; 같이 쓰면 된다.
함수도 가능하다. 함수의 정의를 다른 프로토타입에서 하고, 함수의 원형만 선언해 줘도, 다른 프로토타입의 정의를 공유할 수 있다.(exturn은 붙일 필요 없다)
정적변수
아까 나왔듯이 전역변수는 Data 기억부류에 속한다. 메모리 확보는 스택처럼 자동으로 되는데, 눈여겨봐야 될 점은, 언제 메모리 확보가 될까? 스택은 그때그때 메모리가 확보되지만, 데이터는 프로그램이 시작할 때 통째로 메모리가 확보된다.(0이 초깃값이 된다.) 이것이 문제를 만들기도 하는데, 결론은 프로그램이 끝날 때, 통째로 확보된 메모리가 해제되게 된다.
이 데이터 기억부류를 지역변수로도 사용할 수 있을까? static(스토리지 클래스)를 변수 선언 앞에 붙여주면 된다. 그런 경우, 데이터 기억부류에 속하며, 프로그램이 종료될 때까지 계속 값이 유지된다. 사실상 전역변수다.
레지스터변수
register가 기억부류로 붙으면 레지스터변수가 된다. 사실상 자동변수(지역변수)와 똑같은데, 저장 공간을 CPU에서 끌어 쓰는 것이 특징이다.(레지스터를 붙여도 스택으로 쓰이는 경우도 있다) 사실상 무의미해진 변수다. 컴파일러가 알아서 잘 하기에, 알고만 있자.
'c언어 > 워딩(미정리)' 카테고리의 다른 글
재귀호출 (0) | 2019.07.08 |
---|---|
형 한정어, 형재선언, 열거형 상수 (0) | 2019.07.08 |
유틸리티 함수 (0) | 2019.07.08 |
문자열 처리함수 (0) | 2019.07.08 |
문자열의 구분 및 문자 처리 함수 (0) | 2019.07.08 |