Можно ли переслать объявление статического массива
Мне нужно поставить статический массив в файл .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;