Is it possible to forward declare a static array

I need to put a static array into a .cpp file. This array is only used in this .cpp so I want to declare it static. The array definition is quite big, so naturally I want to forward declare it.

static int bigIntArray[5000];

/* other code using bitIntArray */

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

VC 9.0 gives an error: error C2086: 'int bigIntArray[5000]' : redefinition

If I change 'static' to 'extern', the problem goes away but I do not like this solution.

Why I can not forward declare a static variable? Is this required by the C++ standard?

Answers


At the risk of answering a slightly different question (yours was answered well by Charles Bailey), you might want to use an anonymous namespace with an extern. This prevents other translation units from accessing the array.

namespace {
    extern int bigIntArray[5000];
}

// Code that uses bigIntArray

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

This might meet your need.


It is only possible in C++ to forward declare an object if you use the extern keyword and do not specify an initializer. Any other attempt to declare an object will also be a definition. This implies that a forward declared object will have external linkage. It is not possible to forward declare a static object, i.e. one with internal linkage.

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.


What's the problem with putting the definition (which also is a declaration) at the front and doing away with the "forward declaration"?

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

/* other code using bitIntArray */

Some people say the reason is "readability". The original poster didn't mention that as a motivation.

Anyway, I don't think that doing "odd" things justifies "readability". I think creating a new file type (eg, "*.def" below), is odd.

It doesn't seem to matter much (to me at least) where things are defined.

The cleanest, clearest. simplest thing to do is to move the definition to the top (and not be too concerned about "readability").

Other people say use "extern". The problem with that is that it opens the scope (potentially) of the object name beyond the one module.


It's also possible that the original poster doesn't realize that, in this context, "static" is a scope modifier (not a storage modifier.


You can forward declare your array using only extern like this:

extern int bigIntArray[5000];

You can also remove array size

extern int bigIntArray[];

This will tell the compiler that the array is defined somewhere else (later or other translation unit). In your case it will be defined later in the same translation unit as it is static global.

Works for me in VC++ 2010 Express.


I suppose the reason you want to do this is to improve readability by putting the long constant listings at the end of you code, right? An alternative (IMHO neither better nor worse, just different) would be to use a preprocessor include with the definition, such as:

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

Even better, design-wise, would be to declare the array extern in a header, and put the definition in a stand-alone code file...


I had the same problem and my solution was to convert it to one line of numbers only, because any formatting (spaces, newlines, whatever) would not render the data readable anyway :

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

Thus I was able to put it at the start of my source file, note that it works because I don't use word wrapping.


This is an undefined behavior.

Consider this thread for more details:

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

The quotation from this link:

Because pre-1989 linkers varied in their ability to handle "hidden" symbols. If a linker can't cope with two symbols called "foo" in two different translation units that aren't the same object, then the compiler has to resolve the issue at translation - rather than link - time. And many C compilers were one-pass, so they need to assign an address and space to "foo" when they first see it, or at least the first time it's referenced. Hence the restriction.

As the Rationale puts it: "Prior to C90, implementations varied widely with regard to forward referencing identifiers with internal linkage."

Incidentally, the reason it was required to work in a single file for a symbol with external linkage is that the incomplete version ("int foo[];") might have been in a #included header file.


Is it possible to forward declare a static array

I think it is possible to forward declare with the use of pointer if you want to do it with static.

The pointer declaration will serve as your forward declaration. If your /* other code using bitIntArray */ are function definitions which will called be only after you could allocate the memory and initialize them, you can access the elements in the conventional way 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;
}

The array, being of static integers, will be limited to your compilation unit only.

Warning: One should always take such decisions based on your priorities. This way you may increase the readability of the code or whatever other reasons, for which you want forward declaration, but it would be at the expense of heap.

IMO, as D.A has suggested the best option is to use extern within a defined namespace. extern informs the compiler that the variable is defined elsewhere, and the defined namespace will limit its scope only to the units where the namespace will be used.

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

@D. A. answer is best. - bounty to him I concur with @Leafy on that regard.

Want to add that the array size is not needed in the instantiation if all initializers are there.

Also, having the array size up front has the advantage of being able to use 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 };
}

Best solution I could come up with: forward declare a pointer to an array, then define the static static array and assign it to the pointer at the EOF.

static int *bigIntArray;

/* other code using bitIntArray */

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

static int *bigIntArray = _bigIntArray;

Need Your Help

Thymeleaf - custom attribute

spring-mvc thymeleaf

I need to set custom attribute (data-validation-matches-message) value from messages resources.

Google Analytics iOS Campaign Tracking and URL Builder

ios iphone google-analytics

We want to track installs with Google Analytics for our iOS app.