LINUX.ORG.RU

История изменений

Исправление SZT, (текущая версия) :

Уффф... вообще-то с некоторыми «НО» alloca() можно реализовать как «функцию», если у нас будет механизм подобный RAII и если выделять можно необязательно таким же образом, как и обычные локальные переменные(массивы) в стеке. Можно написать простейший стековый аллокатор, сохранять в начале каждой функциии указатель на вершину стека, потом при выходе из функции, в которой наш особый alloca вызывался, этот стек можно подчищать. Выглядеть это будет примерно вот так:

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

char alloc_glob_arr[100500];
char *alloc_ptr = alloc_glob_arr;

void *my_alloca(const size_t sz) // unaligned allocation!!!
{
  void *retval = alloc_ptr;
  if (sizeof(alloc_glob_arr) < alloc_ptr - alloc_glob_arr + sz)
  {
    fprintf(stderr, "ERROR: stack overflow!\n");
    exit(-1);
  }
  alloc_ptr += sz;
  return retval;
}

void free_my_alloca(void *stackptr)
{
  alloc_ptr = stackptr;
}


int main(void) {
  void *stackptr_start = alloc_ptr;
  printf("stack_p = %p\n", alloc_ptr);

  char *alloc_test1 = my_alloca(10);
  printf("stack_p = %p\n", alloc_ptr);

  for(size_t i = 0; i < 10; i++)
  {
    alloc_test1[i] = i;
  }

  char *alloc_test2 = my_alloca(15);
  printf("stack_p = %p\n", alloc_ptr);

  for(size_t i = 0; i < 15; i++)
  {
    alloc_test2[i] = i*2;
  }


  for(size_t i = 0; i < 10; i++)
  {
    printf("%d,", alloc_test1[i]);
  }
  printf("\n");

  for(size_t i = 0; i < 15; i++)
  {
    printf("%d,", alloc_test2[i]);
  }
  printf("\n");

  free_my_alloca(stackptr_start);

  printf("stack_p = %p\n", alloc_ptr);

  return 0;
}

(Не ручаюсь за полную корректность)

По поводу вопроса «а является ли настоящей функцией обычный alloca() из GCC» - думаю что нет, не является. Обычной функцией такое реализовать не выйдет, ну нельзя написать функию, которая резервирует место в стекфрейме вызывающей её функции и возвращает указатель на него ей же без UB.

Исходная версия SZT, :

Уффф... вообще-то с некоторыми «НО» alloca() можно реализовать как «функцию», если у нас будет механизм подобный RAII и если выделять можно необязательно таким же образом, как и обычные локальные переменные в стеке. Можно написать простейший стековый аллокатор, сохранять в начале каждой функциии указатель на вершину стека, потом при выходе из функции, в которой наш особый alloca вызывался, этот стек можно подчищать. Выглядеть это будет примерно вот так:

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

char alloc_glob_arr[100500];
char *alloc_ptr = alloc_glob_arr;

void *my_alloca(const size_t sz) // unaligned allocation!!!
{
  void *retval = alloc_ptr;
  if (sizeof(alloc_glob_arr) < alloc_ptr - alloc_glob_arr + sz)
  {
    fprintf(stderr, "ERROR: stack overflow!\n");
    exit(-1);
  }
  alloc_ptr += sz;
  return retval;
}

void free_my_alloca(void *stackptr)
{
  alloc_ptr = stackptr;
}


int main(void) {
  void *stackptr_start = alloc_ptr;
  printf("stack_p = %p\n", alloc_ptr);

  char *alloc_test1 = my_alloca(10);
  printf("stack_p = %p\n", alloc_ptr);

  for(size_t i = 0; i < 10; i++)
  {
    alloc_test1[i] = i;
  }

  char *alloc_test2 = my_alloca(15);
  printf("stack_p = %p\n", alloc_ptr);

  for(size_t i = 0; i < 15; i++)
  {
    alloc_test2[i] = i*2;
  }


  for(size_t i = 0; i < 10; i++)
  {
    printf("%d,", alloc_test1[i]);
  }
  printf("\n");

  for(size_t i = 0; i < 15; i++)
  {
    printf("%d,", alloc_test2[i]);
  }
  printf("\n");

  free_my_alloca(stackptr_start);

  printf("stack_p = %p\n", alloc_ptr);

  return 0;
}

(Не ручаюсь за полную корректность)

По поводу вопроса «а является ли настоящей функцией обычный alloca() из GCC» - думаю что нет, не является. Обычной функцией такое реализовать не выйдет, ну нельзя написать функию, которая резервирует место в стекфрейме вызывающей её функции и возвращает указатель на него ей же без UB.