C: память стека, goto и "переход в область идентификатора с измененным типом",

Я обнаружил, что это отказывается компилировать:

int test_alloc_stack(int size){
    if(0) goto error; // same issue whatever conditional is used
    int apply[size];
    give_values(apply,size);
    return 1;
    error:
        return 0;
}

Ошибка, которую я получаю, это: "перейти в область идентификатора с измененным типом". Ликвидация линии с помощью "goto" и переход к ошибке решают проблемы.

Если я использую динамическое распределение для применения, проблема также исчезнет. Это прекрасно компилируется:

 int test_alloc_heap(int size){
    if(0) goto error;
    int * apply = calloc(sizeof(int),size);
    give_values(apply,size);
    free(apply);
    return 1;
    error : return 0;
}

Что происходит?

Ответы

Ответ 1

Объявление:

int apply[size];

создает массив переменной длины. Когда он выходит из сферы действия, компилятор должен создать код, который очищает выделение для этого массива. Мне кажется, что входить в сферу действия такого объекта запрещено, потому что некоторым реализациям может потребоваться некоторая инициализация, требуемая для кода очистки, и если вы перейдете в область действия, инициализация будет обойдена.

Если вы переходите к динамическому распределению, инициализация и очистка становятся вашей ответственностью, а не компилятором.

Ответ 2

Это запрещено стандартом:

Стандарт C99, пункт 6.8.6.1

Ограничения

[...] Утверждение goto должно не перепрыгивать извне пределы идентификатора, имеющего переменный модифицированный тип внутри области этого идентификатора.

Это именно то, что делает ваш goto, а именно: прыгать извне рамки apply внутрь.

Вы можете использовать следующее обходное решение для ограничения области apply:

if(0) goto error;

{
    int apply[size];
    give_values(apply,size);
    return 1;
}

error:
return 0;

Ответ 3

Ваш goto позволяет пропустить строку, которая выделяет apply (во время выполнения).

Вы можете решить проблему одним из четырех способов:

1: перепишите свой код, чтобы вы не использовали goto.

2: Переместите объявление apply до goto.

3: измените область действия, чтобы error: вышла за пределы области apply:

int test_alloc_stack(int size){
    if(0) goto error; // same issue whatever conditional is used
    {
        int apply[size];
        give_values(apply,size);
        return 1;
    }
    error:
        return 0;
}

4: измените объявление переменной, чтобы его размер можно было определить во время компиляции.