tags:

views:

358

answers:

5

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?

+2  A: 

First, the forward declaration must not have the static keyword, only the definition. Next, the forward declaration shouldn't define the size of the array.

Working example (tested on vc9):

#include <iostream>

int bigIntArray[];


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

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




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

Static in this case says to the compiler that the variable have to be define only for the current translation unit (the cpp). If your declaration is in a header, you should add extern to be sure the other translation units/cpp (those without the definition) will not have a copy of this array but use the array defined elsewhere (in the cpp it's defined in).

If you set the size of the array, you're defining it: the array variable is just a pointer and by setting the size you're defining "where" (a memory space) it should be defined. Without the size the definition is incomplete but valid for reference : it's a declaration.

Klaim
Static is NOT optional for globals: by default, globals have external linkage.
Adam Rosenfield
Fixed, was not sure.
Klaim
It looks like VC9 is in error here. The first declaration specifies bitIntArray to have external linkage, but it is also a definition because there is no 'extern'. The object type is incomplete, though (an error) and the identifier is then redeclared with internal linkage (another error).
Charles Bailey
Could you please cite the standard? I don't have/know the exact text from the standard but I always assumed (using vcx) that it was fine to not put extern until you have to use the global in other translation unit.
Klaim
3.5/4 [basic.link] says that the name of an object has external linkage unless covered by 3.5/3 i.e. not static or not (const and not extern).7/6 [dcl.dcl] says that an object declaration is also a definition unless it containts extern and does not have an initializer.
Charles Bailey
Just for reference gcc -std=c++98 -pedantic complains with "error: storage size of ‘bigIntArray’ isn't known"
Charles Bailey
A: 

You don't need static, extern will do.

Nikolai N Fetissov
+2  A: 

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.

Charles Bailey
+2  A: 

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 */

===================

More comments.

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.

Readability, I suppose.
Christoffer
You also need this if you have multiple statics that refer to each other in their initializers.
Chris Dodd
A: 

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...

Christoffer