2022.12.25. 최초 작성
변수는 수학적 의미로 변하는 수를 의미한다.
컴퓨터에서는 메모리에 데이터를 기억하는 공간으로 이야기할 수 있는데 컴퓨터가 데이터를 기억하는 방법을 알 필요가 있다.
데이터를 기억하려면 우선 공간 확보가 필요한데 메모리에서 공간은 bit라는 단위로 정의하였다. 1비트는 0 또는 1로 표현할 수 있다.
메모리 반도체는 1bit 단위의 메모리셀이라는 최소 단위가 수십억 개가 모여 이루어져 있다. 메모리셀 1개에는 스위치 역할을 하는 트랜지스터(Transistor)와 전하를 저장하는 콘덴서(Capacitor)로 구성되어있는데 콘덴서에 전하가 저장되어 있으면 1이고 없으면 0이다.
이런 메모리셀이 8개 모여있는 것을 1byte라고 하고 이것은 영문자 1개를 기억하는데 필요한 크기이다.
변수를 선언할 때 필요한 속성에는 이름, 크기, 값, 주소가 있다.
변수의 이름은 프로그램 코드가 실행되는 과정에서 변수를 구분하는 용도이다. 개발자가 프로그래밍할 때도 변수 이름이 필요하다.
변수의 크기는 확보해야 할 메모리 공간의 크기이다. 변수를 선언할 때 필요한 크기만큼 공간을 확보한다.
변수의 값은 확보된 공간에 채우는 데이터이다. 메모리에 저장되는 데이터는 0과 1로 구분되며 2진수로 표현할 수 있다.
변수의 주소는 메모리에서 변수의 위치이다. 번지라고 생각하면 된다. 2진수로 표현할 수 있지만 너무 길어서 보통 16진수로 표현한다. 실제로는 훨씬 길지만 4자리로 생각하면 0000 ~ FFFF 범위를 갖게 된다.
이전 글(변수와 메모리1)에서 메모리의 구조를 논리적으로 코드, 데이터, 힙, 스택 영역으로 구분하였다.
코드영역에는 실행할 코드가 기계어로 저장되어 있어 순서대로 CPU로 전달하여 실행한다.
데이터영역에 저장된 데이터는 프로그램이 실행되는 동안 계속 유지된다. 언제나 필요할 때 접근하여 사용할 수 있기에 편리하다. 하지만 메모리 공간을 계속 차지하기에 무조건 사용하는 좋지 못하다.
힙 영역에는 동적할당 된 값이 저장된다. 동적할당이란 프로그램이 실행 중에 필요한 순간에 공간을 확보하여 데이터를 기억한다. C언어에서는 malloc, 자바에서는 new를 이용할 때 사용되는 공간이다.
필요한 순간에 공간을 확보하고 더 이상 필요가 없어지면 공간을 반납하여 메모리 공간을 효율적으로 사용한다.
스택 영역은 함수가 실행될 때 사용되며 지역변수, 매개변수를 기억하는 공간이다. 함수가 실행될 때 공간을 확보하고 함수가 종료되면 공간을 반납한다.
프로그래머가 변수를 선언할 때는 변수의 이름이 중요하나 CPU의 입장에서는 변수의 이름은 중요하지 않다.
기계어에서는 변수 이름이 아닌 메모리의 주소를 사용한다. 하지만 기계어와 일대일로 대응되는 저급언어인 어셈블리언어만 해도 사람이 프로그램을 작성하기에 변수 이름이 필요하다.
어셈블리어의 변수 정의하는 예시이다.
a db 0x12 ; 1byte 변수 a 정의 b dw 0x1234 ; 2byte 변수 b 정의 c dd 0x12345678 ; 4byte 변수 c 정의 |
변수는 이름뿐 아니라 크기도 중요하다. 어느 정도의 공간을 할당할지 알아야 하기 때문이다.
그래서 변수는 자료형이라는 것을 정해 두었다. 자료형은 변수의 크기와 모양을 의미한다.
C언어의 경우 char 자료형은 1byte 크기를 가지며 문자를 의미한다. int 자료형은 4byte 크기를 가지며 정수(10진수)를 의미한다.
저장되는 위치인 주소는 운영체제가 자동으로 관리해주므로 프로그래머가 정해줄 필요는 없다.
사람이 이해하기 쉬운 언어인 고급언어들(C, Java, Python 등)은 반드시 변수 이름이 필요하다. CPU에 따라 달라지는 저급언어인 어셈블리어도 변수 이름이 필요하지만 실제로 CPU가 실행하는 기계어는 변수 이름 대신 주소를 사용한다.
동적으로 공간을 할당하는 힙 영역에는 변수의 이름을 쓸 수 없다고 했는데 왜 그런지 생각해보자.
동적할당을 한다는 것은 프로그램이 실행 중에 사용자의 입력에 따라 변수에 공간을 할당하는 것을 의미한다.
예를 들면 학급에 새로운 전학생이 왔을 때이다. 기존에 학생 수가 20명이면 학생의 성적을 관리하는 프로그램은 20명 학생의 성적정보를 기억할 만큼 메모리 공간을 확보하여 성적을 처리한다. 전학생이 추가되면 프로그램에서 인원 정보를 1명 추가해주고 21명의 학생 정보를 관리해야 한다.
언제 전학생이 올지 모르므로 미리 넉넉히 공간을 만들어 두는 방법도 있지만 공간의 낭비가 심하며 비효율적이다. 넉넉히 예상하여 변수를 만들어 두어도 부족할 수 있다.
그렇다면 필요할 때 프로그램 사용자가 학생 수를 변경할 수 있어야 하는데 이것은 메모리에서 동적으로 공간을 할당하는 것이다.
변수가 생성될 위치인 주소는 운영체제가 알아서 확보하고 크기는 사용자가 입력한 학생 수에 따라 정해질 수 있다. 하지만 변수 이름은 프로그래밍할 때 정해야 한다.
이전 글(변수와 메모리1)에서 봤던 C언어 코드를 다시 보면 변수 c는 스택 영역의 참조변수(포인터 변수)이고 malloc에서 크기를 int 변수의 크기만큼 정하여 동적 할당한다.
#include<stdio.h>
#include<stdlib.h>
int a = 10;
void main() {
int b = 20;
printf("a : %d, b : %d\n", a, b);
int* c = (int*)malloc(sizeof(int));
*c = 30;
printf("c : %d\n", *c);
free(c);
}
동적 할당된 크기가 int 크기로 정하였으니 4byte이고 위치는 힙 영역의 적당한 곳에 운영체제가 알아서 정할 것이다. 힙 영역은 동적으로 언제 만들어질지 알 수 없는 공간이므로 이름을 미리 정해 둘 수 없다. 대신 스택이나 데이터영역에 참조변수를 만들고 참조변수가 힙 영역에 만들어진 공간의 주소를 기억한다.
int 자료형이면 4byte인데 메모리는 1byte 단위로 주소를 가진다. 그렇다면 참조변수(포인터 변수)인 c는 4개의 주소를 기억해야 할까? 그럴 필요는 없다. 맨 앞의 대표하는 주소 하나만 기억하면 된다.
int 자료형으로 힙 영역에 동적 할당된 공간은 연속된 메모리 공간이고, 4byte라는 크기를 알기 때문에 맨 앞에 대표하는 주소 하나만 알아도 된다.
위 그림에서 스택 영역에 있는 참조변수 c에는 123a라는 주소가 2진수로 저장되어 있다.
변수 a와 b는 직접 값을 가지는 int 변수여서 다른 곳의 값을 참조하지 않는다. 프로그래머가 코딩할 때 변수 이름을 이용해 그 변수의 공간에 저장된 값을 사용하는 것이고 컴퓨터는 기계어 코드에서 변수 이름과 1대1로 매칭된 주소를 사용하는 것이다.
주소만 아는 것이 아니라 크기도 알기 때문에 맨 앞의 시작 주소부터 연속된 공간을 필요한 만큼 사용할 수 있다.
정리하면 메모리 공간은 1byte 단위로 관리되며 필요한 크기만큼 사용한다. 시작 주소를 기준으로 몇 byte를 연속으로 사용하는 개념이다.
그렇다면 변수를 선언한다는 것은 해당 크기만큼 칸막이가 생기는 것일까? 그것은 아니다.
칸막이가 없기에 잘못하면 약속된 크기가 아닌 옆에 남의 영역을 침범할 수도 있다.
이것은 보안 문제가 될 수도 있는데 버퍼 오버플로우(Buffer Overflow)라고 한다. 이 내용은 다음에 따로 정리할 예정이다.
'자료구조' 카테고리의 다른 글
변수와 메모리 1 (메모리 구조를 중점으로) (0) | 2022.12.02 |
---|