Подтвердить что ты не робот

Массив переменной длины в середине struct - почему этот C-код действителен для gcc

Есть какой-то странный код, использующий VLA (массивы переменной длины), который обрабатывается как Valid 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?
4b9b3361

Ответ 1

GCC не позволяет его компилировать с помощью -std=c99 -pedantic-errors. VLA внутри структуры, по-видимому, является (плохо документированной) нестандартной функцией GNU C. См. это.

Ответ 2

В стандарте довольно ясно, что VLA не разрешены в struct:

6.7.2.1 Спецификации структуры и объединения

9 - член структуры или объединения может иметь любой полный тип объекта, отличный от измененный тип. [...]

Изменчивые типы (как и ожидалось) могут быть получены из массива переменной длины (например, путем добавления размеров массива или cv-классификаторов):

6.7.6 Деклараторы

3 - [...] Если во вложенной последовательности деклараторов в полном declarator, существует декларатор, определяющий тип массива переменной длины, тип, указанный полным декларатором, называется изменчивым. Кроме того, любой тип, полученный путем вывода типа декларатора из измененного типа, сам по себе изменен.

Ответ 3

Авторы стандарта C89 признали, что во многих реализациях реализованы полезные функции, которые могут быть непрактичными для других реализаций, и признали это как хорошее. Стандарт был предназначен как минимальный набор требований к реализации; он никогда не собирался препятствовать реализации от предоставления функций, выходящих за рамки этого.

Стандарт требует, чтобы, если соответствующая реализация позволяет объявить массив переменной длины в структуре, определенной в области блока, она должна либо документировать такое поведение, как расширение, либо выдавать диагностику, когда код содержит такое объявление. Поскольку реализация будет бесплатной для обработки кода, однако после выдачи такой диагностики, независимо от того, документирует ли она расширение, требование о расширении документа может быть только применимо только к расширениям, которые не генерируют диагностику. Это, в свою очередь, предполагает, что такие вещи должны быть допустимы.

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