null function pointer?

  • Thread starter Alexei A. Frounze
  • Start date
T

Tim Rentsch

Keith Thompson said:
I'm not entirely sure of that myself. Actually, I just hadn't thought
about the void* case.


C99 6.2.5p20 says:

A _pointer type_ may be derived from a function type, an object
type, or an incomplete type, called the _referenced type_.

which seems to imply three different classes of pointers. On the
other hand, 7.18.1.4 is titled "Integer types capable of holding
object pointers", but it talks only about pointers to void (which
themselves, of course can hold the values of any object pointers).

I wouldn't be surprised if the Standard wasn't completely consistent
on this point. My earlier point, however, was about interpreting
casual conversation rather than interpreting language in the
Standard. If I hear someone say "object pointer" I usually expect
that they mean either a "pointer to object type" or "pointer to
incomplete type", unless there is some kind of explicit statement
to the contrary.

In any case, the conversion from void* to a function pointer type
occurs *only* for null pointer constants. It's a special case, which
is why I didn't think of it.

Yes, that's really all I was meaning to say.
 
T

Tim Rentsch

pete said:
Tim said:
pete said:
Chris Torek wrote:

There is no conversion, explicit or implicit,
defined between object pointers and function pointers

Tim Rentsch wrote:
Technically not quite correct. The code

int (*pf)(void);

pf = (void*)0;

converts an object pointer value to a function pointer.
It's true, the object pointer expression in this
case is also a null pointer constant,
but the expression still yields a value of object pointer type,
and that value is converted by the assignment.

No.
(void *) is a pointer to an incomplete type,
not a pointer to an object type.

Indeed, although "pointer to incomplete [data] type" could be
considered a sub-group of "pointer to object type", or more
generically, "data pointer" -- to be distinguished from "function
pointer", a la Harvard architectures in general.

No.
In C, there's three kinds of types:
1 object
2 incomplete
3 function

What Keith Thompson wrote is just simply and completely
accurate and useful to know, as far as C is concerned.

1. That presumes it's possible to assign only one meaning to what
Keith wrote.

2. It's common usage in ordinary discussions for "object pointer" to
mean a pointer to an object type or to an incomplete type. (Not
the only usage, but one common usage.) To pretend otherwise is,
well, pretending.

I'm not agreeing.
I don't know which interpretation Keith intended, but certainly
more than one interpretation is possible.

The more obvious interpretation is that there's no definition
for conversions between object addresses and function addresses.

So you agree that more than one interpretation is possible?
Otherwise saying "the more obvious interpretation" seems like it
doesn't make much sense.

I don't see any point in contradicting his statement.

I wasn't meaning to contradict his statement, only to clarify it.

As well as not pointing to any object type
(void *)0 doesn't point to any object.
"object pointer" doesn't describe (void *)0
any better than "function pointer" does.

Tthe relationship between
(void *)0 and pointers to object types,
is exactly the same as the relationship between
(void *)0 and pointers to function types.

There's no special relationship between (void *)0
concerning objects versus functions.
null pointers are of both pointer to object types
and pointer to function types.

(void *) is as much of a function pointer
as it is an object pointer,
that is to say "it isn't either".

If you want to take the position that "object pointer" never is
heard or intended to mean anything other than (as language in the
Standard would say it) "pointer to object type", I suppose that's
up to you. It does seem counterproductive though to assume that's
what was meant after it was explicitly stated otherwise.
 
C

Chris Torek

Chris said:
... although "pointer to incomplete [data] type" could be
considered a sub-group of "pointer to object type", or more
generically, "data pointer" -- to be distinguished from "function
pointer", a la Harvard architectures in general.

No.
In C, there's three kinds of types:
1 object
2 incomplete
3 function

That is what the C standards say, yes. But if we look at the
three types, we find that (with one exception), incomplete
types can always be completed later, and when they are, they
become object types. Thus, ignoring the one exception for
the moment, a pointer to an incomplete type must be somehow
"convert-able" to a pointer to an object type, in case the
incomplete type is completed.

The one exception is "void *". But "void *" is required to use
the same representation as "char *", which is a pointer to an
object type.

Thus, in a purely theoretical sense -- not what the C standard
says, but rather what we can deduce from it -- a pointer to an
incomplete type can "be considered" to fall into the same overall
class as "pointer to object type", as I said. This is *not* the
case for "pointer to function type", and we have real examples
of machines on which these two "pointer classes" are significantly
different. The best example is probably the IBM AS/400; but
some other systems provide similar demonstrations: it is not
all that unusual to find systems where sizeof(void *) and
sizeof(void (*)(void)) are wildly different.

Of course, there were machines where sizeof(void *) and sizeof(int *)
were different as well; but the C standard *does* require that a
valid pointer value of type "int *" be store-able in an object of
type "void *". The resulting value, when converted back to "int *",
must compare equal to, and be just as useful as, the original
"int *" pointer.

In effect, on machines that might "want to" have separate address
spaces for "char" vs "int", the language forces them to use the
same space (perhaps with a few extra bits or bytes of information,
as on the Cray or PR1ME). This is distinct from machines that
"want to" have separate spaces for data and instructions; C allows
them to have their way.
 
K

Keith Thompson

Chris Torek said:
Chris said:
... although "pointer to incomplete [data] type" could be
considered a sub-group of "pointer to object type", or more
generically, "data pointer" -- to be distinguished from "function
pointer", a la Harvard architectures in general.

No.
In C, there's three kinds of types:
1 object
2 incomplete
3 function

That is what the C standards say, yes. But if we look at the
three types, we find that (with one exception), incomplete
types can always be completed later, and when they are, they
become object types. Thus, ignoring the one exception for
the moment, a pointer to an incomplete type must be somehow
"convert-able" to a pointer to an object type, in case the
incomplete type is completed.

The one exception is "void *". But "void *" is required to use
the same representation as "char *", which is a pointer to an
object type.

Thus, in a purely theoretical sense -- not what the C standard
says, but rather what we can deduce from it -- a pointer to an
incomplete type can "be considered" to fall into the same overall
class as "pointer to object type", as I said. This is *not* the
case for "pointer to function type", and we have real examples
of machines on which these two "pointer classes" are significantly
different. The best example is probably the IBM AS/400; but
some other systems provide similar demonstrations: it is not
all that unusual to find systems where sizeof(void *) and
sizeof(void (*)(void)) are wildly different.
[snip]

One way to look at it is as a hierarchy of pointer types (though I
don't think the standard discusses it in those terms). There are three
groupings: object pointers, pointers to incomplete types, and function
pointers. Object pointers and pointers to incomplete types together
form a group separate from function pointers. Object pointers can
be further subdivided; for example, struct and union pointers form a
subgroup because they're all required to have the same representation.
(Or can struct pointers have a different representation from union
pointers? I don't remember.) At the lowest level, each pointer type
is distinct. The whole thing forms a tree with two or three major
groupings near the root and infinitely many leaves.
 
S

S.Tobias

Keith Thompson said:
Chris Torek said:
Chris Torek wrote:
... although "pointer to incomplete [data] type" could be
considered a sub-group of "pointer to object type", or more
generically, "data pointer" -- to be distinguished from "function
pointer", a la Harvard architectures in general.

No.
In C, there's three kinds of types:
1 object
2 incomplete
3 function
[snip]

One way to look at it is as a hierarchy of pointer types (though I
don't think the standard discusses it in those terms). There are three
groupings: object pointers, pointers to incomplete types, and function
pointers. Object pointers and pointers to incomplete types together
form a group separate from function pointers. Object pointers can
be further subdivided; for example, struct and union pointers form a
subgroup because they're all required to have the same representation.
(Or can struct pointers have a different representation from union
pointers? I don't remember.) At the lowest level, each pointer type
is distinct. The whole thing forms a tree with two or three major
groupings near the root and infinitely many leaves.

Pointers to object types and pointers to incomplete types
are collectively called "object pointers" (once in a footnote,
and once in a section title). There's no need to introduce
more confusion.

Struct pointers must have same representation as each other.
Same for union ptrs.
 
M

Michael Wojcik

I think this is much clearer in Sea, the C-like language that is
virtually 100% identical to ANSI C, except for two things:

- Neither 0 nor (void *)0 are ever "a null pointer constant".
The code fragment:

int *p = 0;

is valid C, but an error in Sea.

- In Sea, the null pointer constant can only be spelled "nil",
which is a keyword:

int *p = nil;

sets p such that it is valid, but does not point to anything.

In Sea, is {0} a valid initializer for any (complete) object type?
If so, the first rule is arguably violated; if not, I for one
wouldn't use it.

--
Michael Wojcik (e-mail address removed)

Maybe, but it can't compete with _SNA Formats_ for intricate plot
twists. "This format is used only when byte 5, bit 1 is set to 1
(i.e., when generalized PIU trace data is included)" - brilliant!
 
D

Dave Thompson

On 12 Oct 2005 13:54:04 GMT said:
I think this is much clearer in Sea, the C-like language that is
virtually 100% identical to ANSI C, except for [null pointers] <snip>
(One of these days I should hack up gcc a bit and produce gcsea.)

Surely gseac. Attempting to pronounce which irresistibly reminds me
of the occasional C-SPANi carriage of Ireland's parliament "Dial" (?)
whose prime minister's title is pronounced roughly "tee-shuck".

- David.Thompson1 at worldnet.att.net
 
T

Tim Rentsch

One way to look at [how different kinds of pointer types
should be distinguished] is as a hierarchy of pointer types (though I
don't think the standard discusses it in those terms). There are three
groupings: object pointers, pointers to incomplete types, and function
pointers. Object pointers and pointers to incomplete types together
form a group separate from function pointers. Object pointers can
be further subdivided; for example, struct and union pointers form a
subgroup because they're all required to have the same representation.
(Or can struct pointers have a different representation from union
pointers? I don't remember.) At the lowest level, each pointer type
is distinct. The whole thing forms a tree with two or three major
groupings near the root and infinitely many leaves.

Just a few observations:

1. A type may be incomplete in one usage and complete in
another usage, yet be the same type. For example:

struct foo *f = 0;
...
struct foo { ... } some_foo;
...
struct foo *g = &some_foo;

Does 'struct foo *' belong under the pointer to object type
branch or the pointer to incomplete type branch?

2. Two types may "belong together" because they have the
same representation and alignment requirements, yet one
of them can be a pointer to a complete type and another
be a pointer to an incomplete type. The obvious example
is 'char *' and 'void *'.


Don't get me wrong, I think Keith's idea of organizing
pointer types into some kind of hierarchy is a useful
one; however, choosing "pointers to object types" and
"pointer to incomplete types" as major branches near
the root may lead to some difficulties.
 
K

Keith Thompson

Tim Rentsch said:
One way to look at [how different kinds of pointer types
should be distinguished] is as a hierarchy of pointer types (though I
don't think the standard discusses it in those terms). There are three
groupings: object pointers, pointers to incomplete types, and function
pointers. Object pointers and pointers to incomplete types together
form a group separate from function pointers. Object pointers can
be further subdivided; for example, struct and union pointers form a
subgroup because they're all required to have the same representation.
(Or can struct pointers have a different representation from union
pointers? I don't remember.) At the lowest level, each pointer type
is distinct. The whole thing forms a tree with two or three major
groupings near the root and infinitely many leaves.

Just a few observations:

1. A type may be incomplete in one usage and complete in
another usage, yet be the same type. For example:

struct foo *f = 0;
...
struct foo { ... } some_foo;
...
struct foo *g = &some_foo;

Does 'struct foo *' belong under the pointer to object type
branch or the pointer to incomplete type branch?

Good point.
2. Two types may "belong together" because they have the
same representation and alignment requirements, yet one
of them can be a pointer to a complete type and another
be a pointer to an incomplete type. The obvious example
is 'char *' and 'void *'.

I still tend to think that void* should be in a separate category from
ordinary pointer-to-object types, with the relationship between void*
and the pointer-to-character types showing up as link across the
hierarchy.
Don't get me wrong, I think Keith's idea of organizing
pointer types into some kind of hierarchy is a useful
one; however, choosing "pointers to object types" and
"pointer to incomplete types" as major branches near
the root may lead to some difficulties.

Agreed. I'm not as enamored of the idea as I was when I came up with
it off the top of my head for my previous post. To construct a
hierarchy like this, you really need a clear idea of the criteria for
putting something in one place rather than another. There aren't
really any such criteria inherent in the language.

I think the idea is potentially useful, but if there's a conflict with
the language definition, the language definition wins.
 
S

S.Tobias

Keith Thompson said:
Tim Rentsch said:
One way to look at [how different kinds of pointer types
should be distinguished] is as a hierarchy of pointer types (though I
don't think the standard discusses it in those terms). There are three
groupings: object pointers, pointers to incomplete types, and function
pointers. Object pointers and pointers to incomplete types together
form a group separate from function pointers. Object pointers can
be further subdivided; for example, struct and union pointers form a
subgroup because they're all required to have the same representation.
(Or can struct pointers have a different representation from union
pointers? I don't remember.) At the lowest level, each pointer type
is distinct. The whole thing forms a tree with two or three major
groupings near the root and infinitely many leaves.

Just a few observations:

1. A type may be incomplete in one usage and complete in
another usage, yet be the same type. For example:

struct foo *f = 0;
...
struct foo { ... } some_foo;
...
struct foo *g = &some_foo;

Does 'struct foo *' belong under the pointer to object type
branch or the pointer to incomplete type branch?

Good point.
I don't think so. `struct foo *' means different types at different
places. After `struct foo' definition `struct foo' type becomes
complete (is a different type now). We might say that the type of
`f' as declared (strictly speaking, if it was declared in a separate
translation unit) and `g' are not the same (albeit compatible).

What's more, the type of existing identifiers is completed too,
so after the struct definition, `f' has a different (complete) type
than it had before (incomplete). IOW, in the same TU you cannot
have both complete and incomplete struct types with the same tag
at the same place. So in the above example, `f' and `g' do have
the same type.

Cf. 6.2.5p.22 (it's p.23 in n869.txt), 6.7.2.1p.7 (p.6 in n869.txt)
and 6.7.2.3p7p8.
 
T

Tim Rentsch

S.Tobias said:
Keith Thompson said:
Tim Rentsch said:
[snip]

One way to look at [how different kinds of pointer types
should be distinguished] is as a hierarchy of pointer types (though I
don't think the standard discusses it in those terms). There are three
groupings: object pointers, pointers to incomplete types, and function
pointers. Object pointers and pointers to incomplete types together
form a group separate from function pointers. Object pointers can
be further subdivided; for example, struct and union pointers form a
subgroup because they're all required to have the same representation.
(Or can struct pointers have a different representation from union
pointers? I don't remember.) At the lowest level, each pointer type
is distinct. The whole thing forms a tree with two or three major
groupings near the root and infinitely many leaves.

Just a few observations:

1. A type may be incomplete in one usage and complete in
another usage, yet be the same type. For example:

struct foo *f = 0;
...
struct foo { ... } some_foo;
...
struct foo *g = &some_foo;

Does 'struct foo *' belong under the pointer to object type
branch or the pointer to incomplete type branch?

Good point.
I don't think so. `struct foo *' means different types at different
places. After `struct foo' definition `struct foo' type becomes
complete (is a different type now). We might say that the type of
`f' as declared (strictly speaking, if it was declared in a separate
translation unit) and `g' are not the same (albeit compatible).

I believe you are just wrong:

6.7.2.3

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 incomplete until the closing brace of the list
defining the content, and complete thereafter.
 
S

S.Tobias

Tim Rentsch said:
....

I believe you are just wrong:

6.7.2.3

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 incomplete until the closing brace of the list
defining the content, and complete thereafter.

This doesn't contradict anything what I have said so far. At each
point of the code in your example in all declarations `struct foo'
specifier designates the same type, hence we infer that both `f'
and `g' have the same type (ptr to complete type; because both
declarations have the same scope and use the same struct tag).
This is what I said before (snipped).

However before the struct definition, where the identifier `g'
is not declared yet, `struct foo' designates incomplete type, and
`f' is a pointer to incomplete type. There's no contradiction.

A type cannot be both complete and incomplete. `f' has a different
type before and after the struct definition, but `f' has the same
type as `g' (in the area where `g' is declared).
 
T

Tim Rentsch

S.Tobias said:
This doesn't contradict anything what I have said so far. At each
point of the code in your example in all declarations `struct foo'
specifier designates the same type, hence we infer that both `f'
and `g' have the same type (ptr to complete type; because both
declarations have the same scope and use the same struct tag).
This is what I said before (snipped).

However before the struct definition, where the identifier `g'
is not declared yet, `struct foo' designates incomplete type, and
`f' is a pointer to incomplete type. There's no contradiction.

A type cannot be both complete and incomplete. `f' has a different
type before and after the struct definition, but `f' has the same
type as `g' (in the area where `g' is declared).

Please read the cited paragraph again. The reference in the
second sentence to "the type" clearly means that there is only
one type, not two. Completing a previously incomplete structure
type doesn't create a new type; the language here is plain
and unambiguous.
 
N

Netocrat

]
f we look at the three [C] types, we find that (with one
exception), incomplete types can always be completed later, and when
they are, they become object types. [...]
The one exception is "void *". But "void *" is required to use the same
representation as "char *", which is a pointer to an object type.


I'm reading that as "the only incompletable type is void". We can add
to that flexible array members at the end of structs in C99.

[well written exposition of why the two basic pointer types in C are
"function" and "object" omitted]
 
S

S.Tobias

Tim Rentsch said:
Please read the cited paragraph again. The reference in the
second sentence to "the type" clearly means that there is only
one type, not two.

Because at each point there is only one struct type.
It refers to the type declared by the said declarations (which might
be a completed type since the time it was declared - back in time,
so to say).

The first sentence is a rule to rely on, it doesn't say that
the type specifiers mean the same type at all points (well, perhaps
it somehow does, but this is just a poor wording IMO; how would
you make it better?). Together with with p.4 it supplies rules when
two struct type declarations are meant to declare the same type
and when not. Note that they talk about type declarations, not
type specifiers (sometimes a struct/union/enum specifier is a type
declaration, sometimes it's not; see p.5 through 8, they also give
rules what types s/u/e specifiers specify).

I don't understand how you read the second sentence. After translation:
"The colour is red until the closing brace, and green thereafter."
Do you think it means that the the red and green colours are the same?
Completing a previously incomplete structure
type doesn't create a new type; the language here is plain
and unambiguous.

Yes, it does:
6.7.2.1
# Syntax
# 1 struct-or-union-specifier:
# struct-or-union identifieropt { struct-declaration-list }
# struct-or-union identifier
[...]
# 7 The presence of a struct-declaration-list in
# a struct-or-union-specifier declares a new type, within a
# translation unit. [...]



Summary:
struct foo *f = 0; /* declares a new type struct foo */

struct foo { ... } some_foo; /* declares a new type (after `}'); previous
declaration (which is meant to declare the same
type, because it uses the same tag in the same
scope) is completed, and both declare the same
(one) complete type at this point, thus `*f'
and `some_foo' have the same type */

struct foo; /* a type (and tag) declaration, completed by the previous one,
(specifies the same type) */
{
struct foo; /* a type declaration, different type (for different scope) */
}

struct foo *g = &some_foo; /* not a type declaration, struct specifies
the same type as in previous matching tag declaration
(ie. in the same scope) */
 
T

Tim Rentsch

S.Tobias said:
Because at each point there is only one struct type.
It refers to the type declared by the said declarations (which might
be a completed type since the time it was declared - back in time,
so to say).

The first sentence is a rule to rely on, it doesn't say that
the type specifiers mean the same type at all points (well, perhaps
it somehow does, but this is just a poor wording IMO; how would
you make it better?).

I don't see any particular reason to try to find a better wording,
since the present wording apparently is clear enough to all except
perhaps a minority of one person.

Together with with p.4 it supplies rules when
two struct type declarations are meant to declare the same type
and when not. Note that they talk about type declarations, not
type specifiers (sometimes a struct/union/enum specifier is a type
declaration, sometimes it's not; see p.5 through 8, they also give
rules what types s/u/e specifiers specify).

I don't understand how you read the second sentence. After translation:
"The colour is red until the closing brace, and green thereafter."
Do you think it means that the the red and green colours are the same?

Your "translation" leaves a lot to be desired, but consider a related
statement: "the house is red before being painted, and green after
being painted." Yet the house remains the same house.

The property of being complete or incomplete can be different at
different points in a program text. I don't see anything very
mysterious about that. Furthermore it's clear that this notion of
change in completeness is present in the language of the Standard,
which talks of types "being completed", eg, "void is an incomplete
type that cannot be completed".

Completing a previously incomplete structure
type doesn't create a new type; the language here is plain
and unambiguous.

Yes, it does:
6.7.2.1
# Syntax
# 1 struct-or-union-specifier:
# struct-or-union identifieropt { struct-declaration-list }
# struct-or-union identifier
[...]
# 7 The presence of a struct-declaration-list in
# a struct-or-union-specifier declares a new type, within a
# translation unit. [...]

The statement in 6.7.2.1 p7 means only that the type whose contents
are defined by a struct-declaration-list is distinct from a type whose
contents are defined by any other struct-declaration-list.

Summary:
struct foo *f = 0; /* declares a new type struct foo */

struct foo { ... } some_foo; /* declares a new type (after `}'); previous
declaration (which is meant to declare the same
type, because it uses the same tag in the same
scope) is completed, and both declare the same
(one) complete type at this point, thus `*f'
and `some_foo' have the same type */
[snip]

Read 6.7.2.3, all the way through. The (one and only) 'struct foo'
type is introduced by the declaration of 'f'; the declaration list
before 'some_foo' merely completes the specification for the type
introduced at the declaration of 'f'. See 6.7.2.3 p11.
 
S

S.Tobias

Tim Rentsch said:
[snip]
I don't understand how you read the second sentence. After translation:
"The colour is red until the closing brace, and green thereafter."
Do you think it means that the the red and green colours are the same?

Your "translation" leaves a lot to be desired, but consider a related
statement: "the house is red before being painted, and green after
being painted." Yet the house remains the same house.

The property of being complete or incomplete can be different at
different points in a program text. I don't see anything very
mysterious about that.

"Completeness" is not a type's optional property; it is part of its
specification (an attribute).

6.2.5#1:
# [...] Types are partitioned into object types (types that describe
# objects), function types (types that describe functions),
# and incomplete types (types that describe objects but lack
# information needed to determine their sizes).

This makes clear that a type cannot be both complete and incomplete:
"Types are *partitioned* ...". If a type belongs to one group,
it cannot belong to another.

If the Std says a type is incomplete at one place and complete
at some other, it obviously must talk of two distinct types.
Furthermore it's clear that this notion of
change in completeness is present in the language of the Standard,
which talks of types "being completed", eg, "void is an incomplete
type that cannot be completed".
The Std doesn't really define what it means "to complete a type",
and one has to infer it oneself. I have my own idea, but I won't
give it here, as it won't add anything new to the discussion, as
more basic things have to be settled first.

Besides that, an incomplete struct type could be completed in
infinite number of possible ways; do you assume that all those
potential types are the same?

Completing a previously incomplete structure
type doesn't create a new type; the language here is plain
and unambiguous.

Yes, it does:
6.7.2.1
# Syntax
# 1 struct-or-union-specifier:
# struct-or-union identifieropt { struct-declaration-list }
# struct-or-union identifier
[...]
# 7 The presence of a struct-declaration-list in
# a struct-or-union-specifier declares a new type, within a
# translation unit. [...]

The statement in 6.7.2.1 p7 means only that the type whose contents
are defined by a struct-declaration-list is distinct from a type whose
contents are defined by any other struct-declaration-list.
Why should the Standard bother to specify this here? When two struct
specifiers refer to the same type is completely defined in 6.7.2.3,
and is based on tags, tag declarations and scopes. What would change
(according to your interpretation) if that sentence was omitted
(fully or partly)?
Summary:
struct foo *f = 0; /* declares a new type struct foo */

struct foo { ... } some_foo; /* declares a new type (after `}'); previous
declaration (which is meant to declare the same
type, because it uses the same tag in the same
scope) is completed, and both declare the same
(one) complete type at this point, thus `*f'
and `some_foo' have the same type */
[snip]

Read 6.7.2.3, all the way through. The (one and only) 'struct foo'
type is introduced by the declaration of 'f'; the declaration list
before 'some_foo' merely completes the specification for the type
introduced at the declaration of 'f'. See 6.7.2.3 p11.

I'm sorry, I can't see how you can understand the quoted excerpt from
the Standard any other way. It says clearly to me: the second
declaration "declares a *new* type".
 
T

Tim Rentsch

S.Tobias said:
Tim Rentsch said:
6.7.2.3

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 incomplete until the closing brace of the list
defining the content, and complete thereafter.
[snip]
I don't understand how you read the second sentence. After translation:
"The colour is red until the closing brace, and green thereafter."
Do you think it means that the the red and green colours are the same?

Your "translation" leaves a lot to be desired, but consider a related
statement: "the house is red before being painted, and green after
being painted." Yet the house remains the same house.

The property of being complete or incomplete can be different at
different points in a program text. I don't see anything very
mysterious about that.

"Completeness" is not a type's optional property; it is part of its
specification (an attribute).

6.2.5#1:
# [...] Types are partitioned into object types (types that describe
# objects), function types (types that describe functions),
# and incomplete types (types that describe objects but lack
# information needed to determine their sizes).

This makes clear that a type cannot be both complete and incomplete:
"Types are *partitioned* ...". If a type belongs to one group,
it cannot belong to another.

If the Std says a type is incomplete at one place and complete
at some other, it obviously must talk of two distinct types.
Furthermore it's clear that this notion of
change in completeness is present in the language of the Standard,
which talks of types "being completed", eg, "void is an incomplete
type that cannot be completed".
The Std doesn't really define what it means "to complete a type",
and one has to infer it oneself. I have my own idea, but I won't
give it here, as it won't add anything new to the discussion, as
more basic things have to be settled first.

Besides that, an incomplete struct type could be completed in
infinite number of possible ways; do you assume that all those
potential types are the same?

Completing a previously incomplete structure
type doesn't create a new type; the language here is plain
and unambiguous.

Yes, it does:
6.7.2.1
# Syntax
# 1 struct-or-union-specifier:
# struct-or-union identifieropt { struct-declaration-list }
# struct-or-union identifier
[...]
# 7 The presence of a struct-declaration-list in
# a struct-or-union-specifier declares a new type, within a
# translation unit. [...]

The statement in 6.7.2.1 p7 means only that the type whose contents
are defined by a struct-declaration-list is distinct from a type whose
contents are defined by any other struct-declaration-list.
Why should the Standard bother to specify this here? When two struct
specifiers refer to the same type is completely defined in 6.7.2.3,
and is based on tags, tag declarations and scopes. What would change
(according to your interpretation) if that sentence was omitted
(fully or partly)?
Summary:
struct foo *f = 0; /* declares a new type struct foo */

struct foo { ... } some_foo; /* declares a new type (after `}'); previous
declaration (which is meant to declare the same
type, because it uses the same tag in the same
scope) is completed, and both declare the same
(one) complete type at this point, thus `*f'
and `some_foo' have the same type */
[snip]

Read 6.7.2.3, all the way through. The (one and only) 'struct foo'
type is introduced by the declaration of 'f'; the declaration list
before 'some_foo' merely completes the specification for the type
introduced at the declaration of 'f'. See 6.7.2.3 p11.

I'm sorry, I can't see how you can understand the quoted excerpt from
the Standard any other way. It says clearly to me: the second
declaration "declares a *new* type".

Please don't take this the wrong way, but continuing to respond
to the obtuseness in these messages has grown tiresome. If
you're still confused, I suggest printing a copy of the thread
and sitting down with someone you can talk to interactively
and see if they can explain it to you. I'll decline further
comment.
 
N

Netocrat

S.Tobias said:
The property of being complete or incomplete can be different at
different points in a program text. I don't see anything very
mysterious about that.

"Completeness" is not a type's optional property; it is part of its
specification (an attribute).

6.2.5#1:
# [...] Types are partitioned into object types (types that describe
# objects), function types (types that describe functions),
# and incomplete types (types that describe objects but lack
# information needed to determine their sizes).
[...]
Please don't take this the wrong way, but continuing to respond to the
obtuseness in these messages has grown tiresome.

To be fair, although some of Stan's other interpretations seem to be
stretches, he does seem to have identified some inconsistency in the
wording of the standard above.

If Chuck Falconer were around he would likely charge this as a meaningless
angels-on-pinheads debate though - it seems obvious that the intended
outcome of the standard is that a completed type must be treated as
incomplete prior to being completed, in which contexts the quote above
applies. It is nevertheless the same type prior and subsequent to being
completed; inconsistent wording notwithstanding.
 
S

S.Tobias

[discussion snipped]
Please don't take this the wrong way, but continuing to respond
to the obtuseness in these messages has grown tiresome.
^^^^^^^^^^

My whole reasoning has been crushed by this single argument, I guess.
I'm overwhelmed. Now it's the time I shut up, right?
If
you're still confused, I suggest printing a copy of the thread
and sitting down with someone you can talk to interactively
and see if they can explain it to you.

Do you mean to say Usenet is not interactive enough?
I'll decline further
comment.

When I don't want to answer, I just don't answer. I don't mind you
not willing to continue the discussion, but I wish you had finished
it in a nicer manner. Oh, and I probably took "this" the wrong way.

PS. If someone else would be willing to answer my previous arguments,
I'd still be happy to hear from him and respond.
 

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

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top