가변 길이 배열(VLA)이란?
가변 길이 배열(Variable Length Array, VLA)은 컴파일 시점이 아닌 실행 시점에 크기가 결정되는 자동(auto) 배열을 말합니다. 함수 내에서 선언된 지역 배열의 크기를 매개변수 값에 따라 동적으로 정할 수 있어, 고정 크기 배열보다 훨씬 유연한 메모리 활용이 가능합니다.
C 언어는 C99 표준부터 가변 길이 배열을 공식적으로 지원합니다. 다음과 같은 형태로 작성할 수 있습니다.
void make_arr(int n){
int array[n];
}
int main(){
make_arr(10);
}
위 코드에서 배열 array의 크기는 함수 호출 시 전달되는 인자 n에 따라 런타임에 결정됩니다.
C++ 표준에서의 지원 현황
반면 C++의 경우 상황이 다릅니다. C++11까지의 표준에는 가변 길이 배열이라는 개념이 존재하지 않았으며, 배열의 크기는 반드시 상수 표현식(constant-expression)으로 명시해야 했습니다. 따라서 위 코드는 C++11 이하 표준에서는 유효하지 않습니다.
C++14부터는 배열 크기를 단순 표현식(simple expression)으로 지정할 수 있도록 규정이 완화되었지만, 여전히 표준 C++이 VLA를 완전히 보장하는 것은 아닙니다. 참고로 GCC 같은 일부 컴파일러는 자체 확장 기능으로 VLA를 허용하기도 합니다.
예제: 길이 0 배열 멤버를 활용한 구조체
아래 예제는 구조체 마지막에 길이가 0인 배열 멤버(flexible array member)를 두어, 문자열 길이에 딱 맞는 크기만큼 메모리를 계산하고 활용하는 방법을 보여줍니다. 직원 정보를 담는 클래스에 ID, 이름 길이, 실제 할당 크기를 함께 기록합니다.
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
class employee {
public:
int id;
int name_length;
int struct_size;
char emp_name[0];
};
employee *make_emp(struct employee *e, int id, char arr[]) {
e = new employee();
e->id = id;
e->name_length = strlen(arr);
strcpy(e->emp_name, arr);
e->struct_size = ( sizeof(*e) + sizeof(char)*strlen(e->emp_name) );
return e;
}
void disp_emp(struct employee *e) {
cout << "Emp Id:" << e->id << endl;
cout << "Emp Name:" << e->emp_name << endl;
cout << "Name Length:" << e->name_length << endl;
cout << "Allocated:" << e->struct_size << endl;
cout << "---------------------------------------" << endl;
}
int main() {
employee *e1, *e2;
e1 = make_emp(e1, 101, "Jayanta Das");
e2 = make_emp(e2, 201, "Tushar Dey");
disp_emp(e1);
disp_emp(e2);
cout << "Size of student: " << sizeof(employee) << endl;
cout << "Size of student pointer: " << sizeof(e1);
}
실행 결과
Emp Id:101
Emp Name:Jayanta Das
Name Length:11
Allocated:23
---------------------------------------
Emp Id:201
Emp Name:Tushar Dey
Name Length:10
Allocated:22
---------------------------------------
Size of student: 12
Size of student pointer: 8
결과 해석
char emp_name[0]은 실제 공간을 차지하지 않는 길이 0 배열로, 구조체 본체 뒤에 이름 문자열을 이어 붙이는 용도로 사용됩니다. 실제 할당 크기(struct_size)는 구조체 기본 크기(12바이트)에 이름 길이를 더한 값입니다. 예를 들어 'Jayanta Das'는 11글자이므로 12 + 11 = 23바이트가 할당됩니다. 포인터 크기는 64비트 환경 기준 8바이트로 출력됩니다.
실무에서는 가변 길이 데이터를 다룰 때 std::vector나 std::string 같은 표준 컨테이너를 사용하는 것이 훨씬 안전하지만, 임베디드 시스템 등 저수준 메모리 최적화가 필요한 상황에서는 위와 같은 기법이 여전히 활용될 수 있습니다.