是否可以转发声明静态数组

时间:2009-06-01 19:51:05

标签: c++

我需要将静态数组放入.cpp文件中。此数组仅用于此.cpp,因此我想将其声明为静态。数组定义非常大,所以我自然要转发声明它。

static int bigIntArray[5000];

/* other code using bitIntArray */

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

VC 9.0出错:错误C2086:'int bigIntArray [5000]':重新定义

如果我将'static'改为'extern',问题就会消失,但我不喜欢这个解决方案。

为什么我无法转发声明静态变量?这是C ++标准所要求的吗?

11 个答案:

答案 0 :(得分:28)

冒着回答稍微不同的问题的风险(Charles Bailey很好地回答了你的问题),你可能想要使用带有extern的匿名命名空间。这可以防止其他翻译单元访问该阵列。

namespace {
    extern int bigIntArray[5000];
}

// Code that uses bigIntArray

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

这可能符合您的需要。

答案 1 :(得分:23)

如果您使用extern关键字并且未指定初始值设定项,则只能在C ++中转发声明对象。声明对象的任何其他尝试也将是一个定义。这意味着前向声明的对象将具有外部链接。无法转发声明static对象,即具有内部链接的对象。

这与C不同,其中没有初始化程序的任何声明都是暂定定义,可以提供后续定义,但它们必须都指定相同的链接。

答案 2 :(得分:3)

将定义(也是声明)放在前面并取消“前向声明”会有什么问题?

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

/* other code using bitIntArray */

有人说原因是“可读性”。原始海报没有提到这是一种动机。

无论如何,我不认为做“奇怪”的事情证明“可读性”是正确的。我认为创建一个新的文件类型(例如,下面的“* .def”)是奇怪的。

对于事物的定义似乎并不重要(至少对我而言)。

最干净,最清晰。最简单的事情是将定义移到顶部(而不是太在意“可读性”)。

其他人说使用“extern”。问题在于它打开了对象名称的范围(可能)超出了一个模块。


原始海报也可能没有意识到,在这种情况下,“静态”是范围修饰符(不是存储修饰符。

答案 3 :(得分:2)

您可以仅使用extern声明您的数组:

extern int bigIntArray[5000];

您也可以删除数组大小

extern int bigIntArray[];

这将告诉编译器该数组是在其他地方(后来的或其他翻译单元)定义的。在您的情况下,它将在稍后的同一翻译单元中定义,因为它是静态全局。

在VC ++ 2010 Express中为我工作。

答案 4 :(得分:1)

我认为你想要这样做的原因是通过在代码末尾放置长常量列表来提高可读性,对吧? 另一种选择(恕我直言,既不好也不差,只是不同)将使用包含定义的预处理器,例如:

[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,并将定义放在独立的代码文件中......

答案 5 :(得分:1)

我遇到了同样的问题,我的解决办法是将它转换为一行数字,因为任何格式化(空格,换行符等)都不会使数据可读:

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>
};

因此我能够把它放在源文件的开头,请注意它的工作原理是因为我不使用自动换行。

答案 6 :(得分:1)

这是一种未定义的行为。

请考虑此主题以获取更多详细信息:

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

此链接引用:

  

因为1989年以前的联系人处理能力差异很大[&p ;;   符号。如果链接器无法处理两个名为&#34; foo&#34;成两半   不同的翻译单位不是同一个对象,然后是   编译器必须在翻译时解决问题 - 而不是链接 -   时间。许多C编译器都是一次通过,所以他们需要分配一个   地址和空间到&#34; foo&#34;当他们第一次看到它时,或者至少是它   第一次被引用。因此限制。

     

正如基本原理所说:&#34;在C90之前,实施方式各不相同   关于具有内部联系的前向引用标识符。&#34;

     

顺便提一下,它需要在单个文件中工作的原因   带有外部链接的符号是不完整的版本(&#34; int   foo [];&#34;)可能已经在#included头文件中。

答案 7 :(得分:1)

  

是否可以转发声明静态数组

我认为如果你想用静态方法做,可以使用指针转发声明。

指针声明将作为前向声明。如果您的/* 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;
}

答案 8 :(得分:0)

@D。 A.答案是最好的。 - 给他赏金 在这方面我赞同@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 };
}

答案 9 :(得分:0)

我能提出的最佳解决方案:forward声明一个指向数组的指针,然后定义静态静态数组并将其指定给EOF处的指针。

static int *bigIntArray;

/* other code using bitIntArray */

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

static int *bigIntArray = _bigIntArray;

答案 10 :(得分:0)

This is different from C where any declaration without an initializer is a tentative definition, subsequent definitions can be supplied but they must all specify the same linkage.

很高兴知道,这意味着我们不必在 C 前向声明中显式地放置 extern