컴퓨터가 물건을 보관하는 위치를 어떻게 기억합니까?


32

컴퓨터가 변수를 저장할 때 프로그램이 변수의 값을 가져와야 할 때 컴퓨터는 해당 변수의 값을 메모리에서 찾을 위치를 어떻게 알 수 있습니까?


17
그렇지 않습니다. "컴퓨터"는 완전히 잊혀져 있습니다. 모든 주소를 하드 코딩해야합니다. (그것이 조금 단순화되고 있지만 너무 많이는 아닙니다.)
Raphael

1
@Raphael : "기본 주소를 하드 코딩해야한다"고 일반화하자.
phresnel

변수를 선언 할 때마다 코드 실행을 담당하는 프로그램은 변수 이름과 함께 주소를 해시 테이블 (일명 네임 스페이스)에 포함시킵니다. "컴퓨터 프로그램의 구조와 구현 (SICP)"을 읽어 보면 그와 같은 작은 세부 사항에 대해 잘 알게됩니다.
Abhirath Mahipal

소스 프로그램은 변수를 사용합니다. 컴파일러 또는 해석기는이를 구현하는 방법을 결정합니다. 컴퓨터가 실행할 명령을 생성하고 해당 명령이 이전 명령이 저장된 위치에서 값을 가져와야합니다.
PJTraill

1
@AbhirathMahipal : 변수는 컴파일 타임이나 런타임에 주소를 가질 필요가 없습니다; "네임 스페이스"는 언어 개념이며 테이블 (해시 또는 기타)은 구현 세부 사항입니다. 프로그램이 실행될 때 이름이 nod로 유지되어야합니다.
PJTraill

답변:


31

멋진 컴파일러 구성의 세계를 살펴볼 것을 제안합니다! 답은 약간 복잡한 과정이라는 것입니다.

직관을 제공하기 위해 변수 이름은 순전히 프로그래머를 위해 존재한다는 것을 기억하십시오. 컴퓨터는 결국 모든 것을 주소로 바꿉니다.

지역 변수는 스택에 (일반적으로) 저장됩니다. 즉, 함수 호출을 나타내는 데이터 구조의 일부입니다. 함수를보고 함수가 사용할 변수의 전체 목록을 결정할 수 있으므로 컴파일러는이 함수에 필요한 변수 수와 각 변수에 필요한 공간을 확인할 수 있습니다.

스택 포인터라고하는 약간의 마술이 있습니다. 이것은 현재 스택이 시작되는 위치의 주소를 항상 저장하는 레지스터입니다.

각 변수에는 "스택 오프셋"이 주어지며, 이는 스택에서 저장되는 위치입니다. 그런 다음 프로그램이 변수에 액세스해야 할 때 x컴파일러는 x로 대체 하여 STACK_POINTER + x_offset메모리에 저장된 실제 물리적 위치를 얻습니다.

C 또는 C ++ 를 사용 malloc하거나 사용할 때 포인터를 다시 얻는 이유가 여기에 있습니다 new. 힙 할당 값이 메모리에서 정확히 어디에 있는지 확인할 수 없으므로 포인터를 유지해야합니다. 해당 포인터는 스택에 있지만 힙을 가리 킵니다.

함수 호출 및 리턴을위한 스택 업데이트에 대한 세부 사항은 복잡하므로 관심이있는 경우 Dragon Book 또는 Tiger Book을 권장 합니다.


24

컴퓨터가 변수를 저장할 때 프로그램이 변수의 값을 가져와야 할 때 컴퓨터는 해당 변수의 값을 메모리에서 찾을 위치를 어떻게 알 수 있습니까?

프로그램이 알려줍니다. 컴퓨터에는 기본적으로 "변수"라는 개념이 없습니다. 이는 전적으로 고급 언어입니다!

C 프로그램은 다음과 같습니다.

int main(void)
{
    int a = 1;
    return a + 3;
}

그리고 여기에 컴파일되는 어셈블리 코드가 있습니다 : (로 시작되는 주석 ;)

main:
    ; {
    pushq   %rbp
    movq    %rsp, %rbp

    ; int a = 1
    movl    $1, -4(%rbp)

    ; return a + 3
    movl    -4(%rbp), %eax
    addl    $3, %eax

    ; }
    popq    %rbp
    ret

"int a = 1;" CPU는 "주소 1에 값 1을 저장합니다 (레지스터 rbp 값, -4)"라는 명령을 봅니다. 프로그램이 알려주기 때문에 값 1을 저장할 위치를 알고 있습니다.

마찬가지로, 다음 명령어는 "주소의 값 (레지스터 rbp, 마이너스 4)을 레지스터 eax에로드합니다"라고 말합니다. 컴퓨터는 변수와 같은 것에 대해 알 필요가 없습니다.


2
이것을 jmite의 답변에 연결하려면 %rspCPU의 스택 포인터입니다. %rbp현재 함수가 사용하는 스택의 비트를 나타내는 레지스터입니다. 두 개의 레지스터를 사용하면 디버깅이 간단 해집니다.
MSalters

2

컴파일러 또는 인터프리터가 변수 선언을 발견하면 해당 변수를 저장하는 데 사용할 주소를 결정한 후 주소를 기호 테이블에 기록합니다. 해당 변수에 대한 후속 참조가 발생하면 기호 테이블의 주소가 대체됩니다.

심볼 테이블에 기록 된 주소는 스택 포인터와 같은 레지스터로부터의 오프셋 일 수 있지만 구현 세부 사항입니다.


0

정확한 방법은 구체적으로 무엇을 말하고 있고 얼마나 깊이 가고 싶은지에 달려 있습니다. 예를 들어, 하드 드라이브에 파일을 저장하는 것은 메모리에 저장하거나 데이터베이스에 저장하는 것과 다릅니다. 개념은 비슷하지만. 프로그래밍 수준에서 수행하는 방법은 컴퓨터가 I / O 수준에서 수행하는 방법과는 다른 설명입니다.

대부분의 시스템은 컴퓨터가 데이터를 찾고 액세스 할 수 있도록 일종의 디렉토리 / 인덱스 / 레지스트리 메커니즘을 사용합니다. 이 인덱스 / 디렉토리에는 하나 이상의 키와 데이터가 실제로있는 주소 (하드 드라이브, RAM, 데이터베이스 등)가 포함됩니다.

컴퓨터 프로그램 예

컴퓨터 프로그램은 다양한 방법으로 메모리에 액세스 할 수 있습니다. 일반적으로 운영 체제는 프로그램에 주소 공간을 제공하며 프로그램은 해당 주소 공간으로 원하는 작업을 수행 할 수 있습니다. 메모리 공간 내의 모든 주소에 직접 쓸 수 있으며 원하는 방식으로 추적 할 수 있습니다. 때로는 프로그래밍 언어와 운영 체제에 따라 또는 프로그래머가 선호하는 기술에 따라 달라질 수 있습니다.

다른 답변 중 일부에서 언급했듯이 사용되는 정확한 코딩 또는 프로그래밍은 다르지만 일반적으로 스택과 같은 것을 사용합니다. 여기에는 현재 스택이 시작되는 메모리 위치를 저장하는 레지스터가 있으며 해당 스택에서 함수 또는 변수의 위치를 ​​아는 방법이 있습니다.

많은 고급 프로그래밍 언어에서는 모든 것을 처리합니다. 변수를 선언하고 해당 변수에 무언가를 저장하기 만하면 씬 뒤에 필요한 스택과 배열이 만들어집니다.

그러나 다재다능한 프로그래밍 방식을 고려할 때 프로그래머가 할당 된 공간 내의 모든 주소에 직접 쓰도록 선택할 수 있기 때문에 실제로 한 가지 대답은 없습니다 (프로그래밍 언어를 사용한다고 가정 할 때). 그런 다음 배열에 위치를 저장하거나 프로그램에 하드 코딩 할 수도 있습니다 (예 : 변수 "alpha"는 항상 스택의 시작 부분에 저장되거나 항상 할당 된 메모리의 첫 32 비트에 저장 됨).

개요

따라서 기본적으로 컴퓨터 뒤에 데이터가 저장된 위치를 알려주는 메커니즘이 있어야합니다. 가장 널리 사용되는 방법 중 하나는 키와 메모리 주소를 포함하는 일종의 인덱스 / 디렉토리입니다. 이것은 모든 종류의 방식으로 구현되며 일반적으로 사용자로부터 캡슐화되며 때로는 프로그래머로부터 캡슐화되기도합니다.

참조 : 컴퓨터는 물건을 어디에 저장하는지 어떻게 기억합니까?


0

템플릿과 형식 때문에 알고 있습니다.

프로그램 / 기능 / 컴퓨터는 실제로 어디에 있는지 모릅니다. 단지 특정 장소에 무언가가있을 것으로 기대합니다. 예를 들어 봅시다.

class simpleClass{
    public:
        int varA=58;
        int varB=73;
        simpleClass* nextObject=NULL;
};

새로운 클래스 'simpleClass'에는 3 개의 중요한 변수가 있습니다. 두 개의 정수는 필요할 때 일부 데이터를 포함 할 수 있고 다른 'simpleClass 객체'에 대한 포인터입니다. 단순성을 위해 32 비트 시스템을 사용한다고 가정 해 봅시다. 'gcc'또는 다른 'C'컴파일러는 일부 데이터를 할당하는 데 사용할 템플릿을 만듭니다.

간단한 유형

첫째, 'int'와 같은 간단한 유형의 키워드를 사용하는 경우, 운영 체제에서 실행될 때 데이터가 프로그램에 사용할 수 있습니다. 'int'키워드는 4 바이트 (32 비트)를 할당하고 'long int'는 8 바이트 (64 비트)를 할당합니다.

때로는 셀 단위 방식으로 변수를 메모리에로드 해야하는 명령 바로 뒤에 변수가 올 수 있으므로 의사 어셈블리에서 다음과 같이 표시됩니다.

...
clear register EAX
clear register EBX
load the immediate (next) value into EAX
5
copy the value in register EAX to register EBX
...

이것은 EBX뿐만 아니라 EAX의 값 '5'로 끝납니다.

프로그램이 실행되는 동안 즉각적인로드가이를 참조하고 CPU가이를 건너 뛰기 때문에 '5'를 제외한 모든 명령이 실행 됩니다.

이 방법의 단점은 상수 / 실제로 만 실용적이라는 것입니다. 코드 중간에 배열 / 버퍼 / 문자열을 유지하는 것은 실용적이지 않기 때문입니다. 따라서 일반적으로 대부분의 변수는 프로그램 헤더에 보관됩니다.

이러한 동적 변수 중 하나에 액세스해야하는 경우 즉시 값을 포인터 인 것처럼 취급 할 수 있습니다.

...
clear register EAX
clear register EBX
load the immediate value into EAX
0x0AF2CE66 (Let's say this is the address of a cell containing '5')
load the value pointed to by EAX into EBX
...

이것은 레지스터 EAX의 값 '0x0AF2CE66'과 레지스터 EBX의 '5'값으로 끝납니다. 레지스터에 값을 함께 추가 할 수도 있으므로이 방법을 사용하여 배열 또는 문자열의 요소를 찾을 수 있습니다.

또 다른 중요한 점은 비슷한 방식으로 주소를 사용할 때 값을 저장하여 나중에 해당 셀의 값을 참조 할 수 있다는 것입니다.

복잡한 유형

이 클래스에서 두 개의 객체를 만들면 :

simpleClass newObjA;
simpleClass newObjB;

그런 다음 첫 번째 개체에서 사용 가능한 필드에 두 번째 개체에 대한 포인터를 할당 할 수 있습니다.

newObjA.nextObject=&newObjB;

이제 프로그램은 첫 번째 개체의 포인터 필드에서 두 번째 개체의 주소를 찾을 수 있습니다. 메모리에서 이것은 다음과 같습니다.

newObjA:    58
            73
            &newObjB
            ...
newObjB:    58
            73
            NULL

여기서 주목해야 할 중요한 사실 중 하나는 'newObjA'와 'newObjB'가 컴파일 될 때 이름이 없다는 것입니다. 데이터가 도착할 것으로 예상되는 장소 일뿐입니다. 따라서 & newObjA에 2 개의 셀을 추가하면 'nextObject'역할을하는 셀을 찾습니다. 따라서 'newObjA'의 주소와 'nextObject'셀이 상대적인 위치를 알고 있다면 'newObjB'의 주소를 알 수 있습니다.

...
load the immediate value into EAX
&newObjA
add the immediate value to EAX
2
load the value in EAX into EBX

이는 'EAX'의 '2 + & newObjA'로, 'EBX'의 '& newObjB'로 끝납니다.

템플릿 / 포맷

컴파일러가 클래스 정의를 컴파일하면 실제로 형식을 만드는 방법, 형식을 쓰는 방법 및 형식을 읽는 방법을 컴파일하고 있습니다.

위의 예제는 두 개의 'int'변수가있는 단일 연결 목록의 템플릿입니다. 이러한 종류의 구성은 이진 및 n-ary 트리와 함께 동적 메모리 할당에 매우 중요합니다. n-ary 트리의 실제 응용 프로그램은 파일, 디렉토리 또는 드라이버 / 운영 체제에서 인식하는 기타 인스턴스를 가리키는 디렉토리로 구성된 파일 시스템입니다.

모든 요소에 액세스하려면 구조에서 위아래로 작동하는 인치 웜을 생각해보십시오. 이렇게하면 프로그램 / 기능 / 컴퓨터는 아무것도 알지 못하고 데이터를 이동시키는 명령을 실행합니다.


여기에 사용 된 '템플릿'및 '형식'이라는 단어는 내가 본 컴파일러 또는 컴파일러 교과서에 나타나지 않으며 존재하지 않는 동일한 것에 두 단어를 모두 사용할 이유가 없습니다. 변수에는 주소 및 / 또는 오프셋이 있으므로 알 필요가 있습니다.
user207421

숫자, 파일, 배열 및 변수가 추상화와 마찬가지로 데이터 배열에 대한 추상화이기 때문에 단어를 사용하고 있습니다.
Mr. Minty Fresh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.