Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C와 C++의 가변 길이 배열(VLA) 완벽 이해하기

가변 길이 배열(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::vectorstd::string 같은 표준 컨테이너를 사용하는 것이 훨씬 안전하지만, 임베디드 시스템 등 저수준 메모리 최적화가 필요한 상황에서는 위와 같은 기법이 여전히 활용될 수 있습니다.