статические массивы с неопределенным размером, пустые скобки? - PullRequest
9 голосов
/ 27 апреля 2010

Для фрагмента кода C ++ ниже:

class Foo {
    int a[]; // no error
};

int a[];     // error: storage size of 'a' isn't known

void bar() {
    int a[]; // error: storage size of 'a' isn't known
}

почему переменная-член тоже не вызывает ошибку?и что означает эта переменная-член?

Я использую gcc версии 3.4.5 (mingw-vista special) через CodeBlocks 8.02.

В Visual Studio Express 2008 - Microsoft (RОптимизирующий компилятор C / C ++ 15.00.30729.01 для 80x86, я получил следующие сообщения:

class Foo {
    int a[]; // warning C4200: nonstandard extension used : zero-sized array in struct/union - Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array
};

int a[];

void bar() {
    int a[]; // error C2133: 'a' : unknown size
}

Теперь это тоже нуждается в пояснениях.

Ответы [ 4 ]

12 голосов
/ 27 апреля 2010

Язык C ++ позволяет пропускать размер массива только в неопределяемых объявлениях

extern int a[]; // non-defining declaration - OK in C++

int a[]; // definition - ERROR in C++

int a[5]; // definition - OK, size specified explicitly
int a[] = { 1, 2, 3 }; // definition - OK, size specified implicitly

Для определения размера массива всегда требуются нестатические значения членов класса.

struct S {
  int a[]; // ERROR in C++
};

в то время как статический член класса декараций может опускать размер

struct S {
  static int a[]; // OK in C++
};

( определение того же члена, конечно, должно будет указывать размер).

Любые отклонения от этого поведения могут быть объяснены только расширенным нестандартным поведением вашего компилятора. Возможно, вам следует указать некоторые дополнительные настройки компилятора, чтобы он вел себя более педантично.

8 голосов
/ 27 апреля 2010

C99 поддерживает так называемый «гибкий» элемент массива, которому разрешено быть последним членом структуры. Когда вы динамически выделяете такую ​​структуру, вы можете увеличить запрошенное количество с malloc(), чтобы выделить память для массива.

Некоторые компиляторы добавляют это как расширение C90 и / или C ++.

Таким образом, вы можете иметь следующий код:

struct foo_t {
    int x;
    char buf[];
};


void use_foo(size_t bufSize)
{
    struct foo_t* p = malloc( sizeof( struct foo_t) + bufSize);

    int i;

    for (i = 0; i < bufSize; ++i) {
        p->buf[i] = i;
    }
}

Вы не можете определить структуру с помощью элемента гибкого массива напрямую (как локальную или глобальную / статическую переменную), так как компилятор не будет знать, сколько памяти выделить для него.

Честно говоря, я не уверен, как вы могли бы легко использовать такую ​​вещь с оператором new в C ++ - я думаю, вам нужно было бы выделить память для объекта, используя malloc() и использовать размещение new. Может быть, может быть использована какая-то перегрузка, специфичная для класса / структуры operator new ...

2 голосов
/ 27 апреля 2010
class Foo {
    int a[]; // OK in C, invalid in C++. Does not work with inheritance.
}; // Idea is that structure is "extended" indefinitely by an array.
   // May work on your compiler as an extra feature.

int a[];     // error in C and C++: storage size of 'a' isn't known

void bar() {
    int a[]; // error in C and C++: storage size of 'a' isn't known
}

extern int a[]; // OK: storage size may be declared later.

int a[5]; // declaration of size before use.

Тип массива с неопределенным размером является неполным. 8.3.4 / 1:

Если константное выражение опущено, тип идентификатора D будет «массив-производный-объявитель-тип-списка с неизвестной границей T», неполный тип объекта.

Оно должно быть заполнено для участия в определении, т. Е. Определение a должно содержать спецификацию размера или инициализацию с массивом указанного размера.

0 голосов
/ 27 апреля 2010

Мы использовали это для обозначения записи переменной длины. Что-то вроде заголовочного файла, который содержит информацию о том, сколько структур следует, а затем сами данные Это массив переменной длины, и я обнаружил, что он не поддерживается между компиляторами. Некоторые хотят массив []; и некоторые хотят массив [0]; (старый стиль).

...