Reputation: 1671
From Scope Regions in C++
In C, a struct declaration never generates storage, so C doesn't distinguish struct definitions from other struct declarations. C++ does. In C++, a struct declaration is also a definition if it has a body, as in:
struct widget // a definition { ... };
It's only a declaration if it lacks a body, as in:
struct widget; // just a declaration
So in which cases does struct
declaration generates storage in c++?
Upvotes: 3
Views: 3863
Reputation: 2316
Neither case, really. The problem boils down to the article you linked being at best misleading if not incorrect. The article does not actually say that "generating storage" is a necessary consequence of either but it misleadingly implies it. It's poorly worded, and very imprecise, I think.
Unfortunately the standards aren't very easy to read either, see section 3.1: [http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf][1]
In a nutshell, for structure definitions, a declaration just introduces the type name or structure tag "widget". The definition is a declaration that also provides the body which "defines" the type, like the first example.
The examples from the C++ standard are easier to understand:
Example: all but one of the following are definitions:
int a; // defines a extern const int c = 1; // defines c int f(int x) { return x+a; } // defines f and defines x struct S { int a; int b; }; // defines S, S::a, and S::b struct X { // defines X int x; // defines non-static data member x static int y; // declares static data member y X(): x(0) { } // defines a constructor of X }; int X::y = 1; // defines X::y enum { up, down }; // defines up and down namespace N { int d; } // defines N and N::d namespace N1 = N; // defines N1 X anX; // defines anX
whereas these are just declarations:
extern int a; // declares a extern const int c; // declares c int f(int); // declares f struct S; // declares S typedef int Int; // declares Int extern X anotherX; // declares anotherX using N::d; // declares d
You can "define" a structure which does nothing but define it's layout. But you can also "define" a variable of that structure type. That is when storage might be "generated" (I would maybe say allocated or reserved). When a global variable of the structure type is defined it would result in the binary executable containing a chunk of data the size of the structure. If a local (automatic or stack) variable is defined, it would take up space on the execution stack instead at runtime.
For example, if global (i.e. not in a function):
struct widget x; // defines variable x of type struct widget
// which must be defined somewhere prior
struct widget2; // declares structure widget2
// does nothing except tells the compiler there will be some
// structure definition named widget2 coming later
int fn(widget2 *p); // OK widget2 need only be *declared* first
// NO
// struct widget2 y; // illegal - has not be defined yet
struct widget2 // defines structure widget2 that *would* take up ~8 bytes
{
int thing1;
int thing2;
} y; // defines variable y of type struct widget2 that *does* take up ~8 bytes
struct widget2 z[10]; // defines global variable z that *does* take up ~80 bytes
Maybe another way to look at it is that defining a type is fundamentally different than defining a variable. A type is a concept that exists at compile time and does not take up space at runtime (RTTI ignored).
The C and C++ standards are making the distinction between declare and define because, amongst other reasons, you can not have more than one different definition of something, but you can declare it many times. For variables, definitions roughly coincide with storage allocation, but that isn't the main reason for the distinction.
Upvotes: 3
Reputation: 17638
The following is my paraphrase of the above, hopefully more clear.
struct declarations never generate storage, in either C or C++.
Since C doesn't distinguish struct definitions from other struct declarations, struct definitions never generate storage in C, either.
In C++ the definition of a struct with a static data member (n.b. there is no such thing as a static data member in C) does not generate storage in and by itself, but formally declares its static data member, which is then required to be defined in an enclosing scope - at which point it does in fact generate storage.
In other words, the C++ definition of the struct doesn't technically generate storage, but practically can't be used unless its static data member is defined elsewhere (with the implied storage - even if no objects of that type are ever instantiated).
Relevant C++ references below.
- 3.1.2 Declarations and definitions
struct X { // defines X
static int y; // declares static data member y
};
int X::y = 1; // defines X::y
- 9.4.2 Static data members
9.4.2.1 [...] A static data member is not part of the subobjects of a class. There is only one copy of a static data member shared by all the objects of the class.
[...] The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void.
[...] The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition.
[...] Note: once the static data member has been defined, it exists even if no objects of its class have been created.
Upvotes: 3