Массив переменной длины в середине структуры-почему этот код C действителен для gcc
есть какой-то странный код, использующий VLA (массивы переменной длины), который рассматривается как действительный C (C99, C11) gcc 4.6:
$ cat a.c
int main(int argc,char**argv)
{
struct args_t{
int a;
int params[argc]; // << Wat?
// VLA in the middle of some struct, between other fields
int b;
} args;
args.b=0;
for(args.a=0;args.a<argc;args.a++)
{
args.params[args.a]=argv[0][0];
args.b++;
}
return args.b;
}
этот код компилируется без предупреждений:
$ gcc-4.6 -Wall -std=c99 a.c && echo $?
0
$ ./a.out ; echo $?
1
$ ./a.out 2; echo $?
2
$ ./a.out 2 3; echo $?
3
то же самое для -std=c1x
:
$ gcc-4.6 -Wall -std=c1x a.c && echo $?
0
но это не работает с компилятором Intel C или с Clang+LLVM:
$ icc a.c -o a.icc
a.c(5): warning #1361: variable-length array field type will be treated as zero-length array field type
int params[argc];
^
$ ./a.icc; echo $?
47
$ clang a.c -o a.clang
a.c:5:10: error: fields must have a constant size: 'variable length array in structure' extension will never be supported
int params[argc];
^
1 error generated.
так:
- почему это считается действительным GCC?
- если это расширение GCC, то где оно описал?
- он действителен в стандартах ISO C99 и C11?
3 ответов
GCC не позволяет это, скомпилируйте с -std=c99 -pedantic-errors
. VLA внутри структуры, по-видимому, является (плохо документированной) нестандартной функцией GNU C. посмотреть этот.
стандарт довольно ясно, что VLAs не разрешены в struct
:
6.7.2.1 структура и спецификаторы объединения
9-член структуры или объединения может иметь любой полный тип объекта, кроме изменяемый тип. [...]
изменяемые типы (как и следовало ожидать) являются производными от массива переменной длины (например, путем добавления размеров массива или квалификаторов cv):
6.7.6 Деклараторы
3 - [...] Если во вложенной последовательности деклараторов в полном объеме Декларатор, существует Декларатор, указывающий тип массива переменной длины, тип, указанный полным декларатором, считается изменяемым. Кроме того, любой тип, производный от производного типа Декларатора от изменяемого типа, сам изменяемо модифицируется.
авторы стандарта C89 признали, что во многих реализациях реализованы полезные функции, которые могут быть непрактичными для других реализаций, и признали это как хорошо. Стандарт был задуман как минимальный набор требований для реализации; он никогда не предназначался для того, чтобы препятствовать внедрению дополнительных функций.
стандарт требует, чтобы если соответствующая реализация позволяет массиву переменной длины быть объявленный в структуре, определенной в области блока, он должен либо документировать такое поведение как расширение, либо выдавать диагностику, когда код содержит такое объявление. Поскольку реализация будет свободна обрабатывать код, как ей нравится после выдачи такой диагностики,ли документы расширение, требование документировать расширения может быть применено только к расширениям, которые не генерируют диагностику. Что в свою очередь предполагает, что все должно быть допустимо.
стандарт требует, чтобы расширения не отрицательно влияли на поведение любых строго соответствующих программ, но поскольку такая программа не может содержать объявление VLA в структуре, это требование здесь не является проблемой.