Ben Ben - 2 months ago 16
C Question

Can a structure tag be used before its scope?

In the following example:

#include <stdio.h>
#include <stdlib.h>

struct B b;
struct B{int a;};

struct B;

int main()
{
b.a=3;
printf("%d\n", b.a);
return 0;
}


The file scope of structure tag
B
starts from its first definition/declaration
struct B{int a;};
.
How can
struct B b;
refer to
B
before
B
's scope without error?

Is
struct B;
a structure type declaration, or a structure type definition? Why does it not conflict with the other definition
struct B{int a;};
in the same file scope?

Answer Source

struct B; is a structure declaration. There can be any number of declarations of the same object. For the kinds of objects that have multiple possible declarations, the declarations have to be compatible — for example you can have multiple prototypes for the same function, but they need to use the same argument and return types. For a structure, there's only one way to declare it without defining it, and it just says “there's a structure called B”. So it's ok to repeat struct B; as many times as you want.

struct B{int a;}; is a structure definition. There can only be one definition of a given object. Certain uses of an object require a prior definition, others only require a prior declaration. For example, you can define a variable whose type is a pointer to an undefined structure:

struct S;
struct S *p = NULL;

But you can't define a variable whose type is an undefined structure:

struct S;
struct S s = {0};

The reason for this difference is that a structure that hasn't been defined yet is an incomplete type — a type for which the compiler doesn't have a size. This isn't a problem to define a pointer, but it is a problem to define an object of the incomplete type: the compiler wouldn't know how much memory is required.

At this point, you may wonder why struct B b; is OK. After all, struct B hasn't even been declared, let alone defined.

The first part of why it's ok is that struct B b; declares the structure B in passing. So by the time struct B is needed to do something with b, the structure has just been declared.

The second part of why it's ok is that struct B b; is not exactly a definition. If it was a definition, then the compiler would need to know how much space to reserve, and an incomplete type would not be ok. This is what would happen if the variable was defined in a function:

void f(void) {
    struct B b; // error: storage size of ‘b’ isn’t known
}

But when struct B b; is at the top level of a file, it's a tentative definition. A tentative definition is a declaration; for this, the structure doesn't need to have been defined. When the compiler gets to the end of the file, any tentative definition that hasn't had a proper definition, and for which a definition is needed, becomes a definition. At this point, the structure needs to have been defined. In your example program, b has a tentative definition, and that definition becomes a proper definition at the end of the file.

It's ok to not define the structure if the variable is unused, because it's ok to declare a variable with an incomplete type if the variable is not used.

struct B b;
// end of file

But if the variable is used in a way that requires a complete type, then the structure must have been defined at that point.

struct B b;
void f(void) {
    sizeof(b); // error: invalid application of ‘sizeof’ to incomplete type ‘struct B’
}
struct B{int a;}; // too late