프로그래밍 언어/C & C++ 정리

C++ 기억 존속 시간, 사용 범위

게임 개발 2024. 8. 1. 16:43

 

 

기억 존속 기간

 

 

여러 개의 파일로 이루어진 하나의 프로그램을 만드는 것은 분할 컴파일 과정입니다.

기억 공간의 유형은 여러 파일에 걸쳐 정보를 공유하는 방법에 영향을 주기 때문에,

이러한 것들은 메모리에 대해 알아두는 과정 즉 기억 존속 기간과 관련있습니다.

 

C++은 이러한 기억 존속 기간이 네 가지 유형으로 데이터를 저장합니다.

이 네 가지 유형은 메모리에 데이터를 존속시키는 시간에서 차이가 납니다.

 

  • 자동 기억 존속 시간 (automatic storage duration) :

    함수 매개변수를 포함하여, 함수 정의 안에 선언된 변수는 자동 기억 존속을 가진다.
    그들은 프로그램 실행이 그들을 정의하고 있는 함수나 블록 안으로 들어갈 때 생성된다.
    그리고 그들에게 대입된 메모리는, 프로그램 실행이 해당 함수나 블록을 떠날 때 해제된다.
    C++는 두 종류 자동 변수를 가진다.

  • 정적 기억 존속 시간 (static storage duration) :

    함수 정의의 바깥에서 정의된 변수 또는 키워드 static을 사용하여 정의된 변수는,
    정적 기억 존속 시간 (static storage duration)을 가진다.
    그들은 프로그램이 실행되는 전체 시간 동안 존속한다.
    C++는 세 종류의 정적 변수를 가딘다.

  • 쓰레드 기억 존속 시간 (Thread Storage Duration(C++ 11)) : 

    요즘은 멀티코어 프로세서가 많이 사용되는데,
    이것은 여러 작업을 동시에 처리할 수 있는 CPU를 의미 한다.
    멀티코어 프로세서를 사용하여 연산 작업을 쓰레드(thread) 단위로 쪼개서 처리할 수 있다.

  • 동적 기억 존속 시간 (dynamic storage duration) :

    new 연산자를 사용하여 대입된 메모리는, delete 연산자로 해제되거나
    프로그램이 종료될 때까지, 둘중 어느 것이 먼저 일어날 때까지 존속한다.
    이 메모리는 동적 기억 존속 시간(dynamic storage duration)을 가진다.
    때로는 이 메모리를 자유 공간(free store)이라 부른다.

 

여러 종류의 변수가 사용 범위 안에 들어 있는지 또는 보이는지

(즉, 프로그램이 그 변수를 사용할 수 있는지)에 대한 자세한 사항과,

여러 파이렝 걸쳐서 어던 데이터를 공유할 것인지를 결정하는 링크에 대한 설명을 포함하여,

메모리 관리에 대한 논의를 더 확장해 보자.

 

 

사용 범위와 링크

 

사용 범위(scope)는 어떤 이름이 하나의 파일(번역 단위) 안에서 얼마나 널리 알려지는가를 나타낸다.

예를 들어, 함수 안에서 정의된 변수는 그 함수 안에서만 사용할 수 있고,

다른 함수에서는 사용할 수 없다.

 

그러나 어던 파일에서 함수 정의들의 위에 정의된 변수는 그 아래에 있는 모든 함수에서 사용할 수 있다.

링크(linkage)는 서로 다른 번역 단위들이 이름을 공유하는 것을 말한다.

 

외부 링크(external linkage)를 가진 이름은 여러 파일들이 공유할 수 있다.

 

내부 링크(internal linkage)를 가진 이름은 한 파일 안에 있는 함수들만 공유할 수 있다.

 

자동 변수는 공유되지 않기 때문에 자동 변수의 이름은 링크를 갖지 않는다.

 

하나의 C++ 변수는 몇 가지 사용 범위 중에서 어느 하나를 가질 수 있다.

 

지역 사용 범위 (local scope),

즉 블록 사용 범위(block scope)를 가지는 변수는 그 변수를 정의한 블록에만 알려진다.

 

블록은 중괄호로 묶은 연속된 구문들이다.

예를 들어 함수 몸체는 내부에 다른 블록을 가질 수 있는 블록이다.

 

파일 사용 범위(file scope)라고 부르기도 하는,

전역 사용 범위(global scope)를 가지는 변수는, 그것이 정의된 지점부터

그 아래로 파일 전체에 걸쳐 알려진다.

자동 변수는 지역 사용 범위를 가진다.

 

정적 변수는 그것이 어떻게 정의되는가에 따라 지역 사용 범위와

전역 사용 범위 중에 어느 하나를 가진다.

 

함수 원형 사용 범위 (function prototype scope)에 사용되는 이름은,

매개변수 리스트를 둘러싸고 있는 괄호 안에만 알려진다.

(그렇게 때문에 이름이 무엇이든 상관이 없고, 설령 이름이 업삳고 해도 문제되지 않는다.)

 

클래스 안에서 선언된 멤버는 클래스 사용 범위(class scope)를 가진다.

 

어떤 이름 공간 안에 선언된 변수는 이름 공간 사용 범위(namespace scope)를 가진다.

 

C++ 함수는 전역 사용 범위를 포함하여,

클래스 사용 범위와 이름 공간 사용 범위를 가질 수 있다.

그러나 지역 사용 범위는 가질수 없다.

 

만약에 함수가 지역 사용 범위를 갖는다면, 자기 자신에게만 알려질 것이다.

그렇게 된다면 다른 함수가 그 함수를 호출할 수 없게 되므로,

함수의 기능을 수행할 수 없다.

 

C++의 다양한 기억 공간을 기억 존속 시간, 사용 범위 링크에 의해 그 속성이 구별된다.

C++의 기억 공간을 이들 속성을 통해서 살펴보자.

먼저, 이름이 추가되기 전의 사정을 살펴본 다음,

이름 공간이 상황을 어떻게 바꾸었는지 살펴보자.

 

자동 변수

 

함수 매개변수와, 함수 안에서 선언된 변수는 기본적으로 자동 기억 존속 시간을 가진다.

이들은 또한 지역 사용 범위를 가지며, 링크는 없다.

 

 

자동 변수 초기화

 

자동 변수는, 그 선언에 도달된 시점에서 값을 알 수 있다면,

어떠한 표현식을 사용하더라도 초기화할 수 있다.

 

자동 변수와 스택

 

C++ 컴파일러가 자동 변수를 어떻게 구현하는지를 알면,

자동 변수에 대해 더 많은 것을 이해할 수 있다.

 

함수들이 수시로 시작되고 종료됨에 따라 자동 변수의 개수도 늘어나거나 줄어들기 때문에,

프로그램은 실행 시간 동안에 자동 변수를 스스로 관리 해야 한다.

일반적인 방법은 메모리의 일부를 예약해 두고,

변수들의 생성과 소멸을 스택으로 관리하는 것이다.

 

새로 생성되는 데이터는 먼저 생성된 데이터의 위에 (같은 위치가 아니라 인접한 위치에) 쌓이고,

프로그램이 데이터의 사용을 마치면 그 데이터는 스택에서 제거된다.

 

스택의 기본 크기는 C++마다 다르지만,

일반적으로 사용자가 스택의 크기를 선택할 수 있다.

 

한 포인터는 스택으로 예약한 메모리의 시작 위치인 스택의 바닥을 지시한다.

다른 한 포인터는 다음 번 데이터의 저장을 위해 비어 있는 메모리 위치인 스택의 꼭대기를 지시한다.

함수가 호출되면 그 함수의 자동 변수들이 스택에 추가된다.

이제 꼭대기를 지시하는 포인터는 새로 추가된 변수들을 지나서 새롭게 사용할 수 있는 빈 위치를 지시한다.

 

그런데 그 함수가 종료되면,

새로운 변수가 사용했던 기억 장소는 해제되고,

꼭대기를 지시하는 포인터는 그 함수가 호출되기 이전의 위치를 다시 지시한다.

 

스택은 LIFO(Lastin, Firstout; 후입선출) 설계이다.

이것은 가장 나중에 들어온 변수가 가장 먼저 나간다는 뜻이다.

후입선출 설계는 매개변수의 전달 과정을 간단하게 만든다.

 

함수 호출은 매개변수의 값들을 스택의 꼭대기에 넣고,

꼭대기를 지시하는 포인터를 다시 설정한다.

호출된 함수는 형식 매개변수의 서술을 사용하여 각 매개 변수의 주소를 결정한다.

 

 

레지스터 변수

 

본래 C는 register 키워드를 제공함으로서 컴파일러가

CPU 레지스터를 사용해서 자동 변수를 저장할 것을 제안한다.

아이디어는 변수에 더욱 빨리 접근하는 것을 허용하기 위함이었다.

 

C++11이전의 C++은 하드웨어와 컴파일러가 매우 세밀히 개발된 경우를 제외하고

register키워드가 자주 사용되는 변수라는 의미,

컴파일러가 해당 변수에 특별한 조취를 한다는 의미로 일반화하여 위의 목적을 추구하였습니다.

 

C++11에서는 비록 이러한 것들이 사려졌지만

register 키워드를 어떤 한 변수가 자동적임을 명시하도록 남겨두었다.

register 키워드가 오로지 자동 변수들과 함께 쓰인다고 가정할 때,

register 키워드를 사용해야하는 단 하나의 이유를 꼽는다면,

아마도 사용자가 외부 변수와 동일한 이름을 지닌

어떤 자동 변수를 사용하길 간절히 원한다는 것을 의미하기 때문이다.

 

바로 이것이 auto를 사용하는 본래의 목적이지만, register키워드를 유지하는

가장 중요한 목적은 이 키워드를 사용하는 기존의 코두가 인식이 불가능해지는 것을 막기 위함이다.

 

 

정적 변수

 

C와 마찬가지로는 C++는,

세 가지 유형의 링크(외부 링크, 내부 링크, 링크 없음)를 가지는, 정적 변수를 제공한다.

 

세 가지 유형 모두 프로그램이 실행되는 전체 시간 동안 존속된다.

그들은 자동 변수보다 수명이 길다.

 

정적 존속 시간, 외부 링크

 

외부 연계성을 지닌 변수는 종종 단순히 외부 변수로 부른다.

외부 변수는 정적 저장 기간과 파일 범위를 지닌다.

 

단일 정의 원칙

 

C++에서는 하나의 변수에 대하여 오직 하나의 정의를 부여하는 단일 정의 원칙을 명시하고 있다.

이러한 요구 사항을 충족시키기 위해서,C++은 두 종류의 변수를 선언한다.

 

만약 여러 파일에서 외부 변수가 사용될 경우, 

오직 한 개의 파일이 그 변수에 대한 정의를 지닐 수 있다(유일 정의 원칙).

그러나, 그 변수를 사용하는 다른 모든 파일들은

그 변수를 extern이라는 키워드를 사용해서 선언해 줄 필요가 있다.

 

정적 존속 시간, 내부 링크

파일 사용 범위가 있는 변수에 static 제한자를 적용하면 내부 링크를 부여하게 된다.

내부 링크와 외부 링크의 차이는 다중 파일 프로그램에서 그 의미가 확연하게 드러난다.

 

내부 링크 변수는 그 변수를 포함하고 있는 파일에서만 사용할 수 있지만,

외부 링크 변수는 다른 파일에서도 사용이 가능하다.

 

 

정적 기억 존속 시간, 링크 없음

지금까지 우리는 외부 링크를 가지는 파일 사용 범위의 변수와,

내부 링크를 가지는 파일 사용 범위의 변수를 살펴보았다.

 

이제 정적 기억 존속 시간 변수의 세 번째 멤버를 살펴보자.

그와 같은 변수는 블록 안에서 정의되는 변수에 static 제한자를 적용하여 만든다.

블록

'프로그래밍 언어 > C & C++ 정리' 카테고리의 다른 글

함수 뒤에 const? 너 누군데  (0) 2024.09.25
C++ 람다 식  (1) 2024.09.15
템플릿  (0) 2024.07.31
파일 복사 프로그램  (0) 2024.07.09
파일 읽고 쓰기 - C언어  (0) 2024.07.05