struct type completion

S

S.Tobias

I'm trying to understand how structure type completion works.

# A structure or union type of unknown
# content (as described in 6.7.2.3) is an incomplete type. It
# is completed, for all declarations of that type, by
^^^
# declaring the same structure or union tag with its defining
# content later in the same scope.
^^^^^
(6.2.5#23)

# [#3] All declarations of structure, union, or enumerated
^^^
# types that have the same scope and use the same tag declare
^^^^^^^^^^^^
# the same type. The type is incomplete100) until the
^^^^^^^^^^^^^^
# closing brace of the list defining the content, and complete
# thereafter.
(6.7.2.3#3)
(both excerpts are from n869.txt, but they're the same in the Std)

So (eg. in a file scope):

/* 1 */ struct mystruct object;
/* 2 */ struct mystruct { /*...*/ };

line 1 defines `object' (although at this point the body of `struct
mystruct' is not yet known(?)); and line 1 does not work without
line 2.

What I don't understand is, that the excerpts above seem to dictate
that line 2 fully defines the type for all instances of `struct mystruct'.
The type in line 1 must be a complete type; if it were not, then it would
not be the same type as in line 2, which seems to be required by the
second quote; and - what's obvious - we could not define `object' (we
can't define an object with incomplete type, can we?).

But then further description seems to contradict this: "... incomplete
until the closing brace ...". If the type in line 1 is complete, then
it needn't be completed, and can't of course be incomplete at the
same time.

If I add this definition:
/* test */ int test[sizeof object];
after line 1, then I get a compiler error; whereas I move it after
line 2, everything is okay. In the first case it is stunning
that I can define an object, but I can't take its size.

Could you please explain this to me? - many thanks!
 
L

Lawrence Kirby

I'm trying to understand how structure type completion works.

# A structure or union type of unknown
# content (as described in 6.7.2.3) is an incomplete type. It
# is completed, for all declarations of that type, by
^^^
# declaring the same structure or union tag with its defining
# content later in the same scope.
^^^^^
(6.2.5#23)

# [#3] All declarations of structure, union, or enumerated
^^^
# types that have the same scope and use the same tag declare
^^^^^^^^^^^^
# the same type. The type is incomplete100) until the
^^^^^^^^^^^^^^
# closing brace of the list defining the content, and complete
# thereafter.
(6.7.2.3#3)
(both excerpts are from n869.txt, but they're the same in the Std)

So (eg. in a file scope):

/* 1 */ struct mystruct object;
/* 2 */ struct mystruct { /*...*/ };

line 1 defines `object' (although at this point the body of `struct
mystruct' is not yet known(?)); and line 1 does not work without
line 2.

Line 1 is invalid. When you define an object the type must be complete at
the point of definition, it cannot be completed later. Note that you can
define a pointer to an incomplete type whch is completed later. All
pointer types are object types, even pointers to incomplete or function
types.
What I don't understand is, that the excerpts above seem to dictate that
line 2 fully defines the type for all instances of `struct mystruct'.
The type in line 1 must be a complete type; if it were not, then it
would not be the same type as in line 2, which seems to be required by
the second quote; and - what's obvious - we could not define `object'
(we can't define an object with incomplete type, can we?).

At the point that line 1 is translated its type is incomplete. For any
code after line 2 it would appear complete (except of course that it is
invalid). So taking a valid example

/* 1 */ struct mystruct *ptr;

/* sizeof *ptr is invalid here */

/* 2 */ struct mystruct { /*...*/ };

/* sizeof *ptr is valid here because it is equivalent to
sizeof(struct mystruct) which is now complete */
But then further description seems to contradict this: "... incomplete
until the closing brace ...". If the type in line 1 is complete, then
it needn't be completed, and can't of course be incomplete at the same
time.

A type can be incomplete at one point in the source file and then complete
later on.

Lawrence
 
S

S.Tobias

Thank you very much for answering. However I disagree with you.
I'm trying to understand how structure type completion works.

# A structure or union type of unknown
# content (as described in 6.7.2.3) is an incomplete type. It
# is completed, for all declarations of that type, by
^^^
# declaring the same structure or union tag with its defining
# content later in the same scope.
^^^^^
(6.2.5#23)

# [#3] All declarations of structure, union, or enumerated
^^^
# types that have the same scope and use the same tag declare
^^^^^^^^^^^^
# the same type. The type is incomplete100) until the
^^^^^^^^^^^^^^
# closing brace of the list defining the content, and complete
# thereafter.
(6.7.2.3#3)
(both excerpts are from n869.txt, but they're the same in the Std)

So (eg. in a file scope):

/* 1 */ struct mystruct object;
/* 2 */ struct mystruct { /*...*/ };

line 1 defines `object' (although at this point the body of `struct
mystruct' is not yet known(?)); and line 1 does not work without
line 2.
Line 1 is invalid.

I have tried this code with como and gcc, and both exhibit exactly
same behaviour - try it for yourself: compile as is (ok), delete
line 2 (error), insert line "test" after line 1 (error), move it
after line 2 (ok).
When you define an object the type must be complete at
the point of definition, it cannot be completed later.

Yes, I think so too.
Note that you can
define a pointer to an incomplete type whch is completed later. All
pointer types are object types, even pointers to incomplete or function
types.

I'm quite aware of that. You don't even have to complete the type
(unless you dereference the ptr) - the pointer is still valid. But this
is not what I want to talk about, and I really do mean an object where
I put the identifier `object'.

The code is a corner case I wanted to check after reading the above
quotes from the Standard. I think that they say that struct types
can be completed later. Please pay attention to the words I underlined;
I hope you can either agree to my interpretation, or understand
the reason to my misunderstanding and correct me.

Reminder: identifiers have the same scope, when their scopes end
at the same point. Above, the scopes of the declarations are different
(they start at different places), but both declarations have the same
scope (cf. 6.2.1 p. 6 and 7).
At the point that line 1 is translated its type is incomplete. For any
code after line 2 it would appear complete (except of course that it is
invalid).

I thought so too. But this seems to contradict eg. the second quote
(both in fact): both declarations use the same tag, therefore they
declare the *same* type; a type cannot be both complete and incomplete.

[snipped example for pointers - agree, but a different matter]

I assume the type is complete (first quote), that is, both declarations
declare complete type (whatever incredible that sounds). However
the last sentence of the second quote seems to contradict it:

(As I read it now, I think it may be understood that closing brace
completes the type, even for earlier declarations; hence there would
be no disagreement. But still, the wording is very contrived -
it would be simpler to say the definition of the (complete) struct
type may be found later in the translation unit.)
A type can be incomplete at one point in the source file and then complete
later on.

Hmmm.... I don't have an answer to that, but I strongly disagree.
If one is incomplete, the other complete, then they're different types,
I thought that was pretty logical. Could you give some example, or
a reference (c&v), please?
 
O

Old Wolf

S.Tobias said:
I have tried this code with como and gcc, and both exhibit exactly
same behaviour - try it for yourself: compile as is (ok), delete
line 2 (error), insert line "test" after line 1 (error), move it
after line 2 (ok).

Line 1 is a "tentative definition" (see 6.9.2 in N869).
It is a kind of forward declaration for objects.

To paraphrase the standard, Line 1 declares that 'object' is
the name of an object that will be declared elsewhere in the file.
The object will be of type 'struct mystruct' which is currently
an incomplete type.

If the end of file is reached and 'object' does not have a
full definition (ie. a definition with initializer), then the
compiler will add a line:

struct mystruct object = { 0 };

to the end of the file, and compile that.

Tentative definitions are permitted to have incomplete type,
as long as the type has been completed by the time end-of-file
is reached. If you delete Line 2 you will get a compiler error.

If you put Line 1 and Line 2 inside a function (where tentative
definitions are invalid), you will get a compiler error on Line 1.
 
L

Lawrence Kirby

Thank you very much for answering. However I disagree with you.
I'm trying to understand how structure type completion works.

# A structure or union type of unknown
# content (as described in 6.7.2.3) is an incomplete type. It
# is completed, for all declarations of that type, by
^^^
# declaring the same structure or union tag with its defining
# content later in the same scope.
^^^^^
(6.2.5#23)

# [#3] All declarations of structure, union, or enumerated
^^^
# types that have the same scope and use the same tag declare
^^^^^^^^^^^^
# the same type. The type is incomplete100) until the
^^^^^^^^^^^^^^
# closing brace of the list defining the content, and complete
# thereafter.
(6.7.2.3#3)
(both excerpts are from n869.txt, but they're the same in the Std)

So (eg. in a file scope):

/* 1 */ struct mystruct object;
/* 2 */ struct mystruct { /*...*/ };

line 1 defines `object' (although at this point the body of `struct
mystruct' is not yet known(?)); and line 1 does not work without
line 2.
Line 1 is invalid.

I have tried this code with como and gcc, and both exhibit exactly
same behaviour - try it for yourself: compile as is (ok), delete
line 2 (error), insert line "test" after line 1 (error), move it
after line 2 (ok).

Yes, my error. Tentative definitions are allowed to have incomplete type
as long as they don't have internal linkage, I overlooked the last part.
Yes, I think so too.


I'm quite aware of that. You don't even have to complete the type
(unless you dereference the ptr) - the pointer is still valid. But this
is not what I want to talk about, and I really do mean an object where
I put the identifier `object'.

The code is a corner case I wanted to check after reading the above
quotes from the Standard. I think that they say that struct types
can be completed later. Please pay attention to the words I underlined;
I hope you can either agree to my interpretation, or understand
the reason to my misunderstanding and correct me.

I guess it comes down to what it means by "the same type".
Reminder: identifiers have the same scope, when their scopes end
at the same point. Above, the scopes of the declarations are different
(they start at different places), but both declarations have the same
scope (cf. 6.2.1 p. 6 and 7).

Yes, they have the same scope, and of course the same tag.
I thought so too. But this seems to contradict eg. the second quote
(both in fact): both declarations use the same tag, therefore they
declare the *same* type; a type cannot be both complete and incomplete.

Not at a particular point in the code, but it can at different points in
the code. It is much the same issue as with function prototypes. If you
have

void foo();

foo(x);

void foo(void);

foo(x);

then the rules that apply to the first foo(x); are different to the
second: the second sees the composite type that includes the prototype.
[snipped example for pointers - agree, but a different matter]

I assume the type is complete (first quote), that is, both declarations
declare complete type (whatever incredible that sounds). However
the last sentence of the second quote seems to contradict it:

(As I read it now, I think it may be understood that closing brace
completes the type, even for earlier declarations; hence there would
be no disagreement. But still, the wording is very contrived -
it would be simpler to say the definition of the (complete) struct
type may be found later in the translation unit.)

It is a clear indication that the completeness of a type can change
depending on from what point in the source code you view it.
Hmmm.... I don't have an answer to that, but I strongly disagree.

If one is incomplete, the other complete, then they're different types,
I thought that was pretty logical. Could you give some example, or
a reference (c&v), please?

The wording of the standard you quote above depends on this. A type can
be incomplete at one point in the source code and complete later on. "The
same type" here is simply the opposite of "distinct types".

Consider

{
struct foo { int x } a;
}

{
struct foo { int x } b;
}

a and b have 2 distinct types here, and they are incompatible. Given your
example

the fact that the 2 lines refer to the same type means that the completing
of the type in the second line affects the type of object because they are
the same type. So after line 2 (sizeof object) is valid, which it wouldn't
be if they weren't the same type. I think that is all it is saying.

The wording of the standard may not be perfect in this case but I don't
see room for ambiguity. Maybe you could consider that completing the type
doesn't change the type as such, but just changes what you are allowed to
do with it from that point in the code.

Lawrence
 
S

S.Tobias

Old Wolf said:
S.Tobias said:
S.Tobias wrote:
So (eg. in a file scope):

/* 1 */ struct mystruct object;
/* 2 */ struct mystruct { /*...*/ };
[snip]
I have tried this code with como and gcc, and both exhibit exactly
same behaviour - try it for yourself: compile as is (ok), delete
line 2 (error), insert line "test" after line 1 (error), move it
after line 2 (ok).
Line 1 is a "tentative definition" (see 6.9.2 in N869).
It is a kind of forward declaration for objects.
[snip]

It was an "unfriendly interference of unrelated features".
I should have tested that code in block scope - my fault, I was
too blindly believing what I had understood.
Thank you for your input, that has cleared the way for me!
If you put Line 1 and Line 2 inside a function (where tentative
definitions are invalid), you will get a compiler error on Line 1.

Indeed, 6.7#7 has it explicitly.
 
S

S.Tobias

[/QUOTE]

(I gave more context for the first quote.)

# [#23] An array type of unknown size is an incomplete type.
# It is completed, for an identifier of that type, by
# specifying the size in a later declaration (with internal or
# external linkage). A structure or union type of unknown
# content (as described in 6.7.2.3) is an incomplete type. It
# is completed, for all declarations of that type, by
# declaring the same structure or union tag with its defining
# content later in the same scope.

What I think what this says regarding the structs is this:

With array types:
/* file scope */
int a[], b[];
(`a' and `b' have same type here)
int a[5];
int b[7];
Now we have re-declared and the identifiers `a' and `b' have different
types. We need to re-declare the identifiers to complete their type.

With struct types this is a bit different:
struct s *p;
struct s o; /* in file scope only */
(`*p' and `o' expressions have same, incomplete type)
struct s { ... };
The above definition of `struct s' also causes all previous identifiers
to be *implicitly* re-declared with the new complete type. So from now on
`o' and `*p' are complete types.

I think the following change would improve that fragment:
[...] It is completed, for all declarations [of identifiers]
of that type, by [...]



# [#3] All declarations of structure, union, or enumerated
# types that have the same scope and use the same tag declare
# the same type. The type is incomplete100) until the
# closing brace of the list defining the content, and complete
# thereafter.

I have thought about this one a lot, but I can't reach any conclusion.
[snip]
Yes, my error. Tentative definitions are allowed to have incomplete type
as long as they don't have internal linkage, I overlooked the last part.

Mine too - I thought it would always work, but I hadn't checked it
(thanks, Old Wolf). In fact your previous example with a pointer
to struct was better (more general) - I'm sorry for snipping it
away too hastily.



[...]
I guess it comes down to what it means by "the same type".

8-O You aren't a lawer, are you? ;-)



[snip]
Not at a particular point in the code, but it can at different points in
the code. It is much the same issue as with function prototypes. If you
have
void foo();

void foo(void);

then the rules that apply to the first foo(x); are different to the
second: the second sees the composite type that includes the prototype.

I don't see what you're trying to show me, I don't see anything
strange in here: `foo' is simply re-declared, it had one type
in the first case, and a different type in the second case (it's
allowed for identifiers that have linkage).

It's similar as in my first example a few pages up: both `a' and
`b' start with the same incomplete type, but then each identifier
is re-declared (in different ways) and acquires a different (complete)
type (actually: composite type). The initial and final types are
different.

(It's impossible to make similar parallel for structs, because
their completion is one-way only - a single struct definition
automatically completes all identifiers in the same scope.)



I think that an object type can either be complete or incomplete,
but never both.

"Types are partitioned into object types (types that fully describe
objects), function types (types that describe functions), and incomplete
types (types that describe objects but lack information needed to
determine their sizes)." (6.2.5p1)

For the first thing, I think the word "partitioned" determines it.
For another, a type cannot *fully* describe an object and lack information
about its size at the same time.

When the Standard says "a type is completed", I think it means a new
type is created. I have grep'ed it for "complete" (to find "incomplete",
"complete", "completed", "completely" etc.), and I haven't found anything
to suggest unambiguously anything opposite.

For the last thing: "The presence of a struct-declaration-list
in a struct-or-union-specifier declares a new type, within a
translation unit." (6.7.2.1p7), therefore I think that in:
struct s;
struct s {...};
the types must be different (second type is a *new* type).


The wording of the standard you quote above depends on this. A type can
be incomplete at one point in the source code and complete later on. "The
same type" here is simply the opposite of "distinct types".

{
struct foo { int x } a;
}
{
struct foo { int x } b;
}
a and b have 2 distinct types here, and they are incompatible.

Yes, so what?
Given your
example

[a small "enhancement":]

/* 1 */ struct mystruct object1;
/* 1a */ struct mystruct object1a;
/* 2 */ struct mystruct { /*...*/ } object2;
the fact that the 2 lines refer to the same type means that the completing
of the type in the second line affects the type of object because they are
the same type. So after line 2 (sizeof object) is valid, which it wouldn't
be if they weren't the same type. I think that is all it is saying.

In my view, `object' changes its type[*] after the second
declaration, that's why sizeof object is okay after the second
declaration. However, both declarations declare distinct types.

[*] not because the declarations are "the same type", but because
the first declaration with the same tag is in the same scope, and
this case is covered by the first quote (I think).


# [#3] All declarations of structure, union, or enumerated
# types that have the same scope and use the same tag declare
# the same type.

Following the letter, the above excerpt concerns only (type,
not object) declarations 1 and 2, and not 1a, because 1a is not
a declaration of a type (because previous declaration is visible
- cf. 6.7.2.3p7,8), it merely specifies the same type as in 1.
Both type declarations 1 and 2 have the same scope and the same
tag, therefore (according to the quote) they declare the same
type. (I think that's clear - my understanding and deduction skills
are still in order... right?).

1. I don't agree with that (which I have outlined above).
2. I don't see any need for that. Can you show what would change
if that particular sentence was not there?


Maybe it's just an error in the Standard, or maybe I need a life.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top