Можно ли переслать объявление статического массива

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

static int bigIntArray[5000];

/* other code using bitIntArray */

static int bigIntArray[5000] = {
  0x00, 0x9900, 0xffee,
  ...
};

VC 9.0 дает ошибку: ошибка C2086: 'int bigIntArray [5000]': redefinition

Если я изменю "статический" на "extern", проблема исчезнет, ​​но мне не нравится это решение.

Почему я не могу переслать объявление статической переменной? Требуется ли это по стандарту С++?

Ответы

Ответ 1

Рискуя ответить на несколько иной вопрос (на ваш ответ хорошо ответил Чарльз Бейли), вы можете использовать анонимное пространство имен с внешним. Это предотвращает доступ других блоков перевода к массиву.

namespace {
    extern int bigIntArray[5000];
}

// Code that uses bigIntArray

namespace {
    int bigIntArray[5000] = { ... };
}

Это может удовлетворить ваши потребности.

Ответ 2

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

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

Ответ 3

В чем проблема с помещением определения (которое также является декларацией) на передний план и устранением "форвардной декларации"?

static int bigIntArray[5000] = {  0x00, 0x9900, 0xffee,  ...};

/* other code using bitIntArray */

Некоторые говорят, что причиной является "читаемость". Оригинальный плакат не упоминал об этом как о мотивации.

В любом случае, я не думаю, что выполнение "странных" вещей оправдывает "читаемость". Я думаю, что создание нового типа файла (например, "*.def" ниже) нечетно.

Это, кажется, не имеет большого значения (по крайней мере для меня), где вещи определены.

Самый чистый, ясный. Самое простое - переместить определение в верхнюю часть (и не слишком беспокоиться о "удобочитаемости" ).

Другие люди говорят, что используют "extern". Проблема заключается в том, что он открывает область (потенциально) имени объекта за пределами одного модуля.


Также возможно, что исходный плакат не понимает, что в этом контексте "статический" является модификатором области видимости (не модификатором хранилища.

Ответ 4

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

extern int bigIntArray[5000];

Вы также можете удалить размер массива

extern int bigIntArray[];

Это скажет компилятору, что массив определен где-то в другом месте (позже или другой единицы перевода). В вашем случае это будет определено позже в той же самой единице перевода, что и статическая глобальная.

Работает для меня в VС++ 2010 Express.

Ответ 5

Я полагаю, что причина, по которой вы хотите это сделать, - улучшить читаемость, помещая длинные постоянные списки в конце вашего кода, не так ли? Альтернативой (IMHO, ни лучше, ни хуже, просто отличается) было бы использование препроцессора с определением, например:

[main file]
#include <iostream>
#include "bigIntArray.def"

int main()
{
    for( int i = 0; i < 10000 ; ++i)
    {
        std::cout << bigIntArray[i] << std::endl;
    }

    std::cin.ignore();
    return 0;
}

[bigIntArray.def]
static int bigIntArray[10000] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ... };

Еще лучше, конструктивно, было бы объявить массив extern в заголовке и поместить это определение в отдельный файл кода...

Ответ 6

У меня была та же проблема, и моим решением было преобразовать ее только в одну строку чисел, потому что любое форматирование (пробелы, новые строки и т.д.) в любом случае не отображало бы чтение данных:

static unsigned char XXX_certificate[1376]={
48,130,5,92,48,176,231,119,149,87,108,108,225,239,138,233,91,116,236,200,117,213,130, <cut>
};

Таким образом, я смог поместить его в начало исходного файла, обратите внимание, что он работает, потому что я не использую перенос слов.

Ответ 7

Это поведение undefined.

Рассмотрим эту тему для более подробной информации:

https://groups.google.com/forum/#!topic/comp.lang.c.moderated/bmiF2xMz51U

Цитата из этой ссылки:

Поскольку до 1989 года линкеры отличались своей способностью обрабатывать "скрытые" символы. Если линкер не может справиться с двумя символами, называемыми "foo" в двух разные единицы перевода, которые не являются одним и тем же объектом, тогда компилятор должен решить проблему при переводе, а не ссылку - время. И многие компиляторы C были однопроходными, поэтому им необходимо назначить адрес и пространство для "foo", когда они впервые видят его, или, по крайней мере, первый раз, на который он ссылался. Следовательно, ограничение.

Как объясняет Обоснование: "До C90 реализации сильно различались в отношении идентификаторов прямой ссылки с внутренней связью".

Кстати, причина, по которой он должен был работать в одном файле для символ с внешней связью заключается в том, что неполная версия ( "int foo [];" ), возможно, были в #include заголовочном файле.

Ответ 8

Можно ли переслать объявление статического массива

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

Объявление указателя будет служить вашим объявлением вперед. Если ваш /* other code using bitIntArray */ - это определения функций, которые будут вызваны только после, вы можете выделить память и инициализировать их, вы можете получить доступ к элементам обычным способом bigIntArray [index].

static int *bigIntArray;  // pointer to static integer

/*other code using bitIntArray: function definitions using forward declaration */
int func()
{
        printf("\nfunc %d \n",bigIntArray[3]);
}

int allocate()
{
        bigIntArray = new int[5]{1,2,3,4,5};
}

int main()
{
    allocate();
    func();
    return 0;
}

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

Предупреждение: Всегда следует принимать такие решения на основе ваших приоритетов. Таким образом, вы можете повысить читабельность кода или какие-либо другие причины, для которых требуется форвардное объявление, но оно будет иметь стоимость кучи.

IMO, поскольку D.A предложил лучший вариант - использовать extern в пределах определенного пространства имен. extern сообщает компилятору, что переменная определена в другом месте, а определенное пространство имен ограничивает ее область видимости только единицами, в которых будет использоваться пространство имен.

namespace limited
{
       extern int bigIntArray[];
};
/* other code using bitIntArray */
int func()
{
        using namespace limited;   
        printf("\nfunc %d \n",bigIntArray[3]);
}

namespace limited
{
        int bigIntArray[5] ={1,2,3,4,5};
};

int main()
{
        func();
        return 0;
}

Ответ 9

@D. Ответ лучше. - щедрость ему
Я согласен с @Leafy в этом отношении.

Хотите добавить, что размер массива не требуется в экземпляре, если все инициализаторы существуют.

Кроме того, наличие размера массива на передней панели имеет преимущество в использовании sizeof(bigIntArray)

namespace {
    extern int bigIntArray[5];
}

// Code that uses bigIntArray
void fred() {
  size_t N = sizeof(bigIntArray)/sizeof(bigIntArray[0]);
}

namespace {
    int bigIntArray[/* 5 not needed */] = { 1, 2, 3, 4, 5 };
}

Ответ 10

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

static int *bigIntArray;

/* other code using bitIntArray */

static int _bigIntArray[5000] = {
  0x00, 0x9900, 0xffee,
  ...
};

static int *bigIntArray = _bigIntArray;