Gcc 4.8.2 по умолчанию отлично компилирует и запускает массивы переменной длины

В программировании на C я столкнулся с ситуацией, когда я случайно инициализировал массив с переменным размером, и это сработало. Я провел небольшое исследование, и, по-видимому, массивы переменной длины доступны из компиляции C99. Судя по всему, параметр компиляции GCC 4.8.2 по умолчанию — C98.

Вот код, который я использовал для тестирования:

#include "stdio.h"
#include "stdlib.h" // rand(), srand()
#include "time.h"

void printArray(const char* c) {
    // impossible to get size of c because it returns pointer size
    int array[sizeof(c)/sizeof(char)];
    int i;
    for(i=0; i<(sizeof(c)/sizeof(char))-1; i++) {
        int fill=-1;
        if(c[i]=='a')
            fill = 0;
        else if(c[i]=='b')
            fill = 1;
        array[i]=fill;
    }
    printf("contents of array in binary: \n");
    for(i=0; i<(sizeof(c)/sizeof(char))-1; i++) {
        printf("%d, ", array[i]);
    }
    printf("\n");
}

void printRandomArray() {
    srand(time(NULL));
    // variable length array is possible using C99
    int array[rand()%10];
    int i;
    printf("contents of random array: \n");
    for(i=0; i<(sizeof(array)/sizeof(int)); i++) {
        array[i]=rand()%10;
        printf("%d, ", array[i]);
    }
    printf("\n");
}

int main(int argc, char* argv[]) {
    char c[]="abbabbabbaababababababb";
    printArray(c);

    printRandomArray();
    return 1;
}

printRandomArray() не должен работать, потому что я скомпилировал с использованием GCC 4.8.2 по умолчанию, то есть C98, но он работает. Может ли кто-нибудь объяснить мне, почему это так?


person user3064869    schedule 10.01.2015    source источник
comment
Билл Линч, ваш ответ был именно тем, что я искал, потому что он объяснял, почему вещи, скомпилированные с другой спецификацией C, которые по умолчанию поддерживаются в GCC 4.8.2, почему вы удалили?   -  person user3064869    schedule 10.01.2015
comment
@BillLynch попробуйте -std=c89 -pedantic и -Werror или -Werror=vla   -  person BLUEPIXY    schedule 10.01.2015
comment
@BLUEPIXY: Ах. Ну вот. Спасибо!   -  person Bill Lynch    schedule 10.01.2015
comment
@user3064869: user3064869: Благодаря идее BLUEPIXY о добавлении -pedantic, теперь все в порядке.   -  person Bill Lynch    schedule 10.01.2015


Ответы (3)


Итак, GCC поддерживает две разные версии C89. Он поддерживает c89 и gnu89. Последнее означает, что ряд расширений gcc включен.

Стандартным языком по умолчанию для GCC 4.8.2 является gnu90, который идентичен gnu89. [см. документацию gcc]

Давайте посмотрим на различные предупреждения/ошибки, которые мы получаем, когда используем эти разные языки:

GNU89 и GNU90

[2:10pm][wlynch@apple /tmp] /opt/gcc/4.8.2/bin/gcc            asd.c
[2:10pm][wlynch@apple /tmp] /opt/gcc/4.8.2/bin/gcc -std=gnu89 asd.c
[2:10pm][wlynch@apple /tmp] /opt/gcc/4.8.2/bin/gcc -std=gnu90 asd.c
[2:10pm][wlynch@apple /tmp] 

C89

[2:10pm][wlynch@apple /tmp] /opt/gcc/4.8.2/bin/gcc -std=c89 asd.c
asd.c:2:21: warning: extra tokens at end of #include directive [enabled by default]
 #include "stdlib.h" // rand(), srand()
                     ^
asd.c: In function ‘printArray’:
asd.c:6:5: error: expected expression before ‘/’ token
     // impossible to get size of c because it returns pointer size
     ^
asd.c:15:9: error: ‘array’ undeclared (first use in this function)
         array[i]=fill;
         ^
asd.c:15:9: note: each undeclared identifier is reported only once for each function it appears in
asd.c: In function ‘printRandomArray’:
asd.c:26:5: error: expected expression before ‘/’ token
     // variable length array is possible using C99
     ^
asd.c:30:24: error: ‘array’ undeclared (first use in this function)
     for(i=0; i<(sizeof(array)/sizeof(int)); i++) {
                        ^
[2:10pm][wlynch@apple /tmp] /opt/gcc/4.8.2/bin/gcc -std=gnu89 asd.c
[2:10pm][wlynch@apple /tmp] 

Если мы исправим эти ошибки, а затем также скомпилируем с -pedantic, мы увидим диагностику, которую вы ищете:

[2:28pm][wlynch@apple /tmp] /opt/gcc/4.8.2/bin/gcc -std=c89 -pedantic asd.c
asd.c: In function ‘printRandomArray’:
asd.c:27:5: warning: ISO C90 forbids variable length array ‘array’ [-Wvla]
     int array[rand()%10];
     ^
asd.c:27:5: warning: ISO C90 forbids mixed declarations and code [-Wpedantic]
person Bill Lynch    schedule 10.01.2015

Помимо стандарта C99, GCC также допускает массив переменной длины в качестве расширения:

6.19 Массивы переменной длины.

Автоматические массивы переменной длины разрешены в ISO C99, и в качестве расширения GCC принимает их в режиме C90 и в C++.

Насколько мне известно, GCC 4.8.2 по умолчанию компилирует код в режиме -std=gnu90. Скомпилируйте его с опцией -std=c89 и вы увидите множество предупреждений и ошибок.

person haccks    schedule 10.01.2015
comment
Интересно: GCC (проверено 4.9.1) принимает как -std=c89, так и -std=c90, и это означает в основном одно и то же; то же самое -std=gnu89 и -std=gnu90. - person Jonathan Leffler; 10.01.2015
comment
Я имею в виду только то, что варианты с 89 и 90 считаются эквивалентными и действительными. Код, с которым я возился, содержал комментарии //, а не приведенный выше код VLA, и я получил полуподходящие предупреждения (поскольку код мучительно неясен, если быть точным, тестировал #include <./*some*/header.h>). - person Jonathan Leffler; 10.01.2015
comment
Чтобы было ясно, я ранее вообще не тестировал код в вопросе. Когда я тестировал код в вопросе, комментарии // были отклонены (предупреждены) с помощью -std=c89. Однако VLA не был отклонен, пока я не использовал -std=c89 -pedantic (или -std=gnu89 -pedantic). Даже тогда это было просто предупреждение, пока я не добавил -Werror. - person Jonathan Leffler; 10.01.2015
comment
@Джонатан Леффлер; До сих пор меня удивляет. Если вы скомпилируете тот же код в GCC 4.8.2 с опцией -std=c89, вы получите очень много предупреждений и ошибок. - person haccks; 10.01.2015
comment
Я получил 1 предупреждение и 4 ошибки с кодом из вопроса, скомпилированного в непедантическом режиме C89, в основном из-за комментариев //. С заменой комментариев на /* */ код компилируется чисто без -pedantic и с одним предупреждением об использовании VLA при компиляции с -pedantic. - person Jonathan Leffler; 10.01.2015
comment
@Джонатан Леффлер; То же самое произошло с GCC 4.8.2! Я заменил // на /* */, и код скомпилировался нормально (без флага -Pedantic). о.О - person haccks; 11.01.2015

Во-первых, нет такого понятия, как C98. Это C89/90, затем C95 (который обычно объединяется в C89/90), затем C99 и так далее.

Во-вторых, компилятор GCC в режиме по умолчанию вообще не реализует никакого стандарта C. Язык, который он компилирует, называется GNU C. Нет ничего необычного в том, что он поддерживает VLA по умолчанию. Вы должны вручную настроить GCC, чтобы он соответствовал любому стандарту C. Такие переключатели, как -pedantic или -pedantic-errors, обязательны.

person AnT    schedule 10.01.2015