VLA(배열의 길이가 compile time에 결정되지 않고 runtime에 결정이 되는)의 경우 해당 배열은 stack에서 확보가 되는지, 아니면 heap에서 확보가 되는지를 테스트해 보았습니다.




[code]


#include <stdlib.h>
#include <stdio.h>

void debug(const char* msg, void* p) {
  printf("%s=%p\n", msg, p);
}

void test() {
  char stack = 1;
  debug("stack", &stack); // stack 영역이 대충 어디인지 알아 본다.

  char* heap = (char*)malloc(256);
  debug("heap", heap); // heap 영역이 대충 어디인지 알아 본다.
  free(heap);
}

size_t len1;
size_t len2;
size_t len3;

int main() {
  test();

  scanf("%zu", &len1);
  char arr1[len1]; // 가변 길이 배열.
  debug("arr1", arr1);

  scanf("%zu", &len2);
  char arr2[len2]; // 가변 길이 배열.
  debug("arr2", arr2);

  scanf("%zu", &len3);
  char arr3[len3]; // 가변 길이 배열.
  debug("arr3", arr3);

  printf("%zu\n", arr1 - arr2);
  printf("%zu\n", arr2 - arr3);

  return 0;
}




[result]

입력(각각의 배열의 크기)은 256, 256, 256으로 하였습니다.


stack=0x7fffcb1adddf // stack 영역은 대충 0x7fff... 로 시작하는구나.

heap=0x558d4d96d280 // heap 영역은 대충 0x55... 로 시작하는구나.

256 256 256 // 입력값.

arr1=0x7fffcb1adcf0 // VLA는 stack 영역에 잡힘.

arr2=0x7fffcb1adbf0 // VLA는 stack 영역에 잡힘.

arr3=0x7fffcb1adaf0 // VLA는 stack 영역에 잡힘.

256 // 포인터의 차이는 배열의 크기만큼임.

256 // 포인터의 차이는 배열의 크기만큼임.




[disassemble]
실제로 disassemble된 코드는 다음과 같습니다(필요한 배열의 크기를 16의 배수로 만들어 그만큼 stack 영역을 확보함).

char arr1[len1];
	add    $0xf,%rax
	and    $0xfffffffffffffff0,%rax
	sub    %rax,%rsp




[테스트 환경]

OS : Linux home 4.16.0-kali2-amd64 #1 SMP Debian 4.16.12-1kali1 (2018-05-28) x86_64 GNU/Linux
Compiler : gcc (Debian 7.3.0-23) 7.3.0
Build command : gcc -O2 -g -Wall -o vla_test vla_test.c





ps : 위키( https://en.wikipedia.org/wiki/Variable-length_array )에 다음과 같은 문구가 있으니 참고하시기 바랍니다(VLA는 받드시 stack에서 확보해야 한다는 보장은 없다. 즉 컴파일러 마음대로이다).

  • The GNU C Compiler allocates memory for VLAs with automatic storage duration on the stack. VLAs, like all objects in C, are limited to SIZE_MAX bytes.
  • VLAs can also be allocated on the heap and accessed using a pointer to VLA.