История изменений
Исправление 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.