By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,712 Members | 1,591 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,712 IT Pros & Developers. It's quick & easy.

null function pointer?

P: n/a
Seems like, to make sure that a pointer doesn't point to an object/function,
NULL (or simply 0) is good enough for both kind of pointers, data pointers
and function pointers as per 6.3.2.3:

3 An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
If a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.

4 Conversion of a null pointer to another pointer type yields a null pointer
of that type.
Any two null pointers shall compare equal.

It's a stupid question, but how about comparing data to function pointers?
Null function pointer should compare equal to null data pointer, right,
wrong? Doesn't different bit representation of the pointers make problems
here or are they solved through casting or is this not really
specified/defined?

Alex
Nov 15 '05 #1
Share this Question
Share on Google+
41 Replies


P: n/a
>3 An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
If a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.

4 Conversion of a null pointer to another pointer type yields a null pointer
of that type.
Any two null pointers shall compare equal.

It's a stupid question, but how about comparing data to function pointers?
data pointers and function pointers are often of different sizes.
For example, "middle" and "compact" memory models on i386 in 16-bit
mode. (one has 16-bit data pointers and 32-bit function pointers,
the other has the reverse).
Null function pointer should compare equal to null data pointer, right,
wrong?
I don't think you should do such a comparison. It makes almost
(but not quite) as much sense as comparing a null pointer to
a struct (NOT struct pointer, struct).
Doesn't different bit representation of the pointers make problems
here or are they solved through casting or is this not really
specified/defined?


The whole operation doesn't make any sense, particularly when neither
pointer is null. Deletion of the program would be the best defined
behavior to establish.

Gordon L. Burditt
Nov 15 '05 #2

P: n/a
Alexei A. Frounze wrote:
Seems like, to make sure that a pointer doesn't point to an object/function,
NULL (or simply 0) is good enough for both kind of pointers, data pointers
and function pointers as per 6.3.2.3:

3 An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
If a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.

4 Conversion of a null pointer to another pointer type yields a null pointer
of that type.
Any two null pointers shall compare equal.

It's a stupid question, but how about comparing data to function pointers?
Null function pointer should compare equal to null data pointer, right,
wrong? Doesn't different bit representation of the pointers make problems
here or are they solved through casting or is this not really
specified/defined?

What are you asking? Whether

if ((char*) 0 == (char*) (void (*)()) 0) {
S
} else {
T
}

should always execute S?

Who cares? :-)

S.
Nov 15 '05 #3

P: n/a
"Gordon Burditt" <go***********@burditt.org> wrote in message
news:11*************@corp.supernews.com...
3 An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
If a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.

4 Conversion of a null pointer to another pointer type yields a null pointerof that type.
Any two null pointers shall compare equal.

It's a stupid question, but how about comparing data to function pointers?

data pointers and function pointers are often of different sizes.
For example, "middle" and "compact" memory models on i386 in 16-bit
mode. (one has 16-bit data pointers and 32-bit function pointers,
the other has the reverse).


Right, and I know that.
Null function pointer should compare equal to null data pointer, right,
wrong?


I don't think you should do such a comparison. It makes almost
(but not quite) as much sense as comparing a null pointer to
a struct (NOT struct pointer, struct).
Doesn't different bit representation of the pointers make problems
here or are they solved through casting or is this not really
specified/defined?


The whole operation doesn't make any sense, particularly when neither
pointer is null. Deletion of the program would be the best defined
behavior to establish.


I know, that's why I wrote "*stupid* question" :) It's as stupid as writing
"SLIPPERY WHEN WET" on the bank near the water.
But still both void*p=NULL and void (f*)()=NULL are null pointers as per the
standard and as per the standard such pointers should compare equal... Can
they compare equal when one of them isn't a null pointer? I'm just curious.
Or am I asking too much from the standard? :)

Alex
Nov 15 '05 #4

P: n/a
"Skarmander" <in*****@dontmailme.com> wrote in message
news:43***********************@news.xs4all.nl...
....
What are you asking? Whether

if ((char*) 0 == (char*) (void (*)()) 0) {
S
} else {
T
}

should always execute S?
Exactly. :)
Who cares? :-)


The curious me. I wouldn't write such code in the first place, but the
curiousity... :)

Alex
Nov 15 '05 #5

P: n/a

"Alexei A. Frounze" <al*****@chat.ru> wrote in message
news:3q************@individual.net...
"Gordon Burditt" <go***********@burditt.org> wrote in message
news:11*************@corp.supernews.com... But still both void*p=NULL and void (f*)()=NULL are null pointers as per
the
standard and as per the standard such pointers should compare equal... Can
they compare equal when one of them isn't a null pointer?
Think about what you've asked:

if A == B then does !A == B or !B == A ?

I'm just curious.
Or am I asking too much from the standard? :)


You seem to be asking if logic is logical or not. :-)

-Mike
Nov 15 '05 #6

P: n/a
Alexei A. Frounze wrote:
Seems like, to make sure that a pointer doesn't point to an object/function,
NULL (or simply 0) is good enough for both kind of pointers, data pointers
and function pointers as per 6.3.2.3:

3 An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
If a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.

4 Conversion of a null pointer to another pointer type yields a null pointer
of that type.
Any two null pointers shall compare equal.

It's a stupid question, but how about comparing data to function pointers?
Null function pointer should compare equal to null data pointer, right,
wrong? Doesn't different bit representation of the pointers make problems
here or are they solved through casting or is this not really
specified/defined?


I guess the only thing that should be enabled by that is that
myfunptr == NULL
makes sense, even if NULL is defined as (void *)0. Apart from
that, the comparison of data and function pointers is a Bad Idea
but you already know this :-)
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 15 '05 #7

P: n/a
In article <43***********************@news.xs4all.nl>,
Skarmander <in*****@dontmailme.com> wrote:

if ((char*) 0 == (char*) (void (*)()) 0) {
S
} else {
T
}

should always execute S?

Who cares? :-)


The unprototyped function pointer seems a greater sin to me.
I mean, the last thing you want is a mismatched argument
in your call to the NULL function...
Nov 15 '05 #8

P: n/a
"Alexei A. Frounze" <al*****@chat.ru> writes:
Seems like, to make sure that a pointer doesn't point to an object/function,
NULL (or simply 0) is good enough for both kind of pointers, data pointers
and function pointers as per 6.3.2.3:

3 An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
If a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.

4 Conversion of a null pointer to another pointer type yields a null pointer
of that type.
Any two null pointers shall compare equal.

It's a stupid question, but how about comparing data to function pointers?
Null function pointer should compare equal to null data pointer, right,
wrong? Doesn't different bit representation of the pointers make problems
here or are they solved through casting or is this not really
specified/defined?


I think that "Any two null pointers shall compare equal" is intended
to refer only to pointers that *can* be compared. (And I think the
wording is slightly sloppy.)

You can convert a null pointer constant to either a pointer-to-object
type or to a pointer-to-function type (because the standard
specifically says so). There is no conversion, explicit or implicit,
defined between object pointers and function pointers (though some
implementations might allow such conversions as an extension).

So, given

int *obj_ptr = NULL;
void (*func_ptr)(void) = NULL;

the following expression:

obj_ptr == func_ptr

is a constraint violation, because the types are incompatible. Even
casting one argument to the other's type won't help, because no
conversion is defined.

(Arguments that the comparison doesn't make sense don't really answer
the question. C allows plenty of things that don't make sense. The
relevant point here is that this happens not to be one of them.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #9

P: n/a


Alexei A. Frounze wrote On 10/07/05 16:44,:
Seems like, to make sure that a pointer doesn't point to an object/function,
NULL (or simply 0) is good enough for both kind of pointers, data pointers
and function pointers as per 6.3.2.3:

3 An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
If a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.

4 Conversion of a null pointer to another pointer type yields a null pointer
of that type.
Any two null pointers shall compare equal.

It's a stupid question, but how about comparing data to function pointers?
Null function pointer should compare equal to null data pointer, right,
wrong? Doesn't different bit representation of the pointers make problems
here or are they solved through casting or is this not really
specified/defined?


6.5.9 says of the == and != operators

One of the following shall hold:
-- both operands have arithmetic type;
-- both operands are pointers to qualified or
unqualified versions of compatible types;
-- one operand is a pointer to an object or
incomplete type and the other is a pointer to
a qualified or unqualified version of void; or
-- one operand is a pointer and the other is a
null pointer constant.

The comparison doesn't satisfy any of these constraints,
so a "shall" has been violated and a diagnostic is required.

Thus we can learn that `dataPtr == NULL' is true and
that `funcPtr == NULL' is true, but it is not permitted even
to ask whether `dataPtr == funcPtr'.

The constraints of 6.5.9 seem to contradict the language
in 6.3.2.3; perhaps a query on comp.std.c is in order ...

--
Er*********@sun.com

Nov 15 '05 #10

P: n/a
"Keith Thompson" <ks***@mib.org> wrote in message
news:ln************@nuthaus.mib.org...
"Alexei A. Frounze" <al*****@chat.ru> writes: ....
4 Conversion of a null pointer to another pointer type yields a null pointer of that type.
Any two null pointers shall compare equal.

It's a stupid question, but how about comparing data to function pointers? Null function pointer should compare equal to null data pointer, right,
wrong? Doesn't different bit representation of the pointers make problems here or are they solved through casting or is this not really
specified/defined?


I think that "Any two null pointers shall compare equal" is intended
to refer only to pointers that *can* be compared. (And I think the
wording is slightly sloppy.)

.... So, given

int *obj_ptr = NULL;
void (*func_ptr)(void) = NULL;

the following expression:

obj_ptr == func_ptr

is a constraint violation, because the types are incompatible. Even
casting one argument to the other's type won't help, because no
conversion is defined.

(Arguments that the comparison doesn't make sense don't really answer
the question. C allows plenty of things that don't make sense. The
relevant point here is that this happens not to be one of them.)


OK then, the "wording being slightly sloppy" answers to my question better.
And yes, there's always enough rope in C to shoot in the foot. :)

Alex
Nov 15 '05 #11

P: n/a
Keith Thompson <ks***@mib.org> writes:
There is no conversion, explicit or implicit,
defined between object pointers and function pointers


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. (It could also
be converted by casting, eg, 'pf = (int (*)(void))(void*)0'.)
Nov 15 '05 #12

P: n/a
Tim Rentsch wrote:

Keith Thompson <ks***@mib.org> writes:
There is no conversion, explicit or implicit,
defined between object pointers and function pointers


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.

--
pete
Nov 15 '05 #13

P: n/a
pete <pf*****@mindspring.com> writes:
Tim Rentsch wrote:

Keith Thompson <ks***@mib.org> writes:
There is no conversion, explicit or implicit,
defined between object pointers and function pointers


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.


Sorry, I was using the term informally. The posting I was
responding to (which apparently I snipped too much of),
mentioned only object pointers and function pointers, which
I took to mean pointers to non-function types and to
function types, and that's how the terms were meant to be
taken in my posting. So if Keith meant something different
than what it seemed like he was saying, I withdraw my
followup comment.
Nov 15 '05 #14

P: n/a
>> Keith Thompson <ks***@mib.org> writes:
> 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.

In article <43***********@mindspring.com>
pete <pf*****@mindspring.com> wrote: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.

More important, I think, is that (as Tim Rentsch himself noted)
(void *)0 is not only "the null pointer of type (void *)", it is
also "ankhpee" (ANCP, A Null Pointer Constant). If its "ankhpee-ness"
is considered to override its "null pointer of type void-*"-ness
in this particular case, the problem itself (of mixing "data pointer"
and "function pointer") goes away.

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.

(Note that in Sea, the call:

extern void varfunc(char *, ...);

varfunc("hello", "world", nil);

draws a compile-time diagnostic, because the compiler is missing
the type information required to turn "nil" into an appropriate
null pointer. You must insert a cast to supply the correct type
here.)

In Sea, if we write:

void (*fp)(void) = nil;

it compile just fine -- nil itself is untyped, but produces a "null
function pointer" in the same way it produces a "null data pointer":
a pointer that is valid, but compares unequal to all actual functions
(so "fp != somevoidfunc" is always true).

Because Sea's <stdio.h> et al contain "#define NULL nil", any
well-written C program is a valid Sea program, provided the C
program avoids using the "nil" keyword. Any programmer proficient
in C is also proficient in Sea. The only real difference is that
Sea catches some errors that are common in C. :-)

(One of these days I should hack up gcc a bit and produce gcsea.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #15

P: n/a
In article <di*********@news2.newsguy.com> I wrote, in part:
(void *)0 is not only "the null pointer of type (void *)", it is
also "ankhpee" (ANCP, A Null Pointer Constant).


Of course, this should be ANPC (which implies a different
pronunciation, maybe "an-pee-cee").
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #16

P: n/a
Chris Torek wrote:
Keith Thompson <ks***@mib.org> writes:
> 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.


In article <43***********@mindspring.com>
pete <pf*****@mindspring.com> wrote:
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.

--
pete
Nov 15 '05 #17

P: n/a
pete <pf*****@mindspring.com> writes:
Chris Torek wrote:
> Keith Thompson <ks***@mib.org> writes:
> > 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.


In article <43***********@mindspring.com>
pete <pf*****@mindspring.com> wrote:
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 don't know which interpretation Keith intended, but certainly
more than one interpretation is possible.
Nov 15 '05 #18

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
pete <pf*****@mindspring.com> writes:
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 don't know which interpretation Keith intended,


I'm not entirely sure of that myself. Actually, I just hadn't thought
about the void* case.
but certainly
more than one interpretation is possible.


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

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.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #19

P: n/a
Tim Rentsch wrote:

pete <pf*****@mindspring.com> writes:
Chris Torek wrote:

>> Keith Thompson <ks***@mib.org> writes:
>> > 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.

In article <43***********@mindspring.com>
pete <pf*****@mindspring.com> wrote:
>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.

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

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

--
pete
Nov 15 '05 #20

P: n/a
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
pete <pf*****@mindspring.com> writes:
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 don't know which interpretation Keith intended,


I'm not entirely sure of that myself. Actually, I just hadn't thought
about the void* case.
but certainly
more than one interpretation is possible.


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.
Nov 15 '05 #21

P: n/a
Keith Thompson <ks***@mib.org> wrote:
Chris Torek <no****@torek.net> writes:
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.
In article <43**********@mindspring.com> pete
<pf*****@mindspring.com> wrote:
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.

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #22

P: n/a

In article <di*********@news2.newsguy.com>, Chris Torek <no****@torek.net> writes:

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 mi************@microfocus.com

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!
Nov 15 '05 #23

P: n/a
On 12 Oct 2005 13:54:04 GMT, Chris Torek <no****@torek.net> wrote:
<snip>
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
Nov 15 '05 #24

P: n/a
Keith Thompson <ks***@mib.org> writes:
[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?

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.
Nov 15 '05 #25

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
[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.
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.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #26

P: n/a
Keith Thompson <ks***@mib.org> wrote:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
[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).

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.

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #27

P: n/a
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Keith Thompson <ks***@mib.org> wrote:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
[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.
Nov 15 '05 #28

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Keith Thompson <ks***@mib.org> wrote:
> Tim Rentsch <tx*@alumnus.caltech.edu> writes:
.... >> 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.


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

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #29

P: n/a
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Keith Thompson <ks***@mib.org> wrote:
> Tim Rentsch <tx*@alumnus.caltech.edu> writes:
... >> 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.


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.
Nov 15 '05 #30

P: n/a
On Thu, 13 Oct 2005 00:31:55 +0000, Chris Torek wrote:
[...]
[i]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]

--
http://members.dodo.com.au/~netocrat
Nov 15 '05 #31

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
> "S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
>
>> Keith Thompson <ks***@mib.org> wrote:
>> > Tim Rentsch <tx*@alumnus.caltech.edu> writes:
...
>> >> 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.


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.


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

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #32

P: n/a
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
> "S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
>
>> Keith Thompson <ks***@mib.org> wrote:
>> > Tim Rentsch <tx*@alumnus.caltech.edu> writes:

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

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.


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.
Nov 15 '05 #33

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
>> > 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".

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #34

P: n/a
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:

>> > 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.
Nov 15 '05 #35

P: n/a
On Fri, 21 Oct 2005 12:07:01 -0700, Tim Rentsch wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote: [...]
> 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.

--
http://members.dodo.com.au/~netocrat
Nov 15 '05 #36

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:

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

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #37

P: n/a
Netocrat <ne******@dodo.com.au> writes:
On Fri, 21 Oct 2005 12:07:01 -0700, Tim Rentsch wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote: [...] > 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.


I agree there are passages that may allow more than one interpretation,
at least locally, and perhaps should be reviewed with an eye toward
making the language used in the Standard more clear or less ambiguous.
Having said that, here is the flip side.

1. The different interpretations don't result in any difference in what
C constructs are allowed or what their semantics are.

2. Ergo, whether the different interpretations are reasonable or they
aren't, they are not "right" or "wrong", any more than the lambda
calculus, recursive function theory, or Turing machines are the "right"
interpretation for what is computable; the different interpretations
are simply different ways of thinking about the same logical
consequences. It is "a distinction without being a difference".

3. Because of (2), it seems reasonable to follow the interpretation
that most people use, and that fits better with all the language used
in the Standard. All the developers I've asked (less than half a
dozen, but several) follow the interpretation that there is just one
type, initially incomplete (or undefined) but filled in later; also
the language used in the Standard seems to fit that interpretation
(IMO) better than other interpretations, as I've previously explained.

4. By contrast, it seems that Stan is the only one who follows the
interpretation he puts forward. Perhaps there are others who do also,
but I'm not aware of any.

5. Since it makes no difference to the C language, and since I feel
like I've explained my views adequately, I tried to disengage from the
conversation as politely as possible. Perhaps my phrasing was a little
blunt, but I made an effort to remark only about the content of the
messages and not about who wrote them. If someone has something else
to offer then maybe I'd get interested again; but, usually I try to
avoid "argument for the sake of arguing", and that's where it seems
like things were in the message I last responded to.
Nov 15 '05 #38

P: n/a
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
Netocrat <ne******@dodo.com.au> writes:
On Fri, 21 Oct 2005 12:07:01 -0700, Tim Rentsch wrote:
"S.Tobias" <si***@FamOuS.BedBuG.pAlS.INVALID> writes:
> Tim Rentsch <tx*@alumnus.caltech.edu> wrote: [...]
> > 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).

[...]

I agree there are passages that may allow more than one

interpretation, at least locally, and perhaps should be reviewed with an eye toward
making the language used in the Standard more clear or less ambiguous.
Having said that, here is the flip side.

1. The different interpretations don't result in any difference in what C constructs are allowed or what their semantics are.

2. Ergo, whether the different interpretations are reasonable or they
aren't, they are not "right" or "wrong", any more than the lambda
calculus, recursive function theory, or Turing machines are the "right" interpretation for what is computable; the different interpretations
are simply different ways of thinking about the same logical
consequences. It is "a distinction without being a difference".

3. Because of (2), it seems reasonable to follow the interpretation
that most people use, and that fits better with all the language used
in the Standard. All the developers I've asked (less than half a
dozen, but several) follow the interpretation that there is just one
type, initially incomplete (or undefined) but filled in later; also
the language used in the Standard seems to fit that interpretation
(IMO) better than other interpretations, as I've previously explained.

If someone has something else
to offer ...

If you look for it in quietude, it goes and crouches in clamor;
If you look for it in clamor, then it stands in quietude.
If you want to place it in the realm of nothingness, yet it is a living
thing.
Well, you asked....

--
Mabden
Nov 15 '05 #39

P: n/a
"Mabden" <mabden@sbc_global.net> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message

[snip]
If someone has something else
to offer ...

If you look for it in quietude, it goes and crouches in clamor;
If you look for it in clamor, then it stands in quietude.
If you want to place it in the realm of nothingness, yet it is a living
thing.
Well, you asked....


Sir:

You are guilty of willful misunderstanding. Please
refrain from doing so again in the future.
Nov 15 '05 #40

P: n/a
>In article <di*********@news2.newsguy.com>, Chris Torek
<no****@torek.net> writes:
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 article <di*********@news4.newsguy.com>
Michael Wojcik <mw*****@newsguy.com> wrote:In Sea, is {0} a valid initializer for any (complete) object type?
Presumably "no".
If so, the first rule is arguably violated; if not, I for one
wouldn't use it.


Note that:

struct S { int x; char *p; } var = { 0 };

*would* initialize var.p to nil, so perhaps Sea should allow empty
brackets as the "universal initializer":

complete_object_type var = {};

(Out of curiosity, what is the referent for the pronoun "it" at
the end of the quote above? The language, or {0}?)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #41

P: n/a

In article <dl********@news4.newsguy.com>, Chris Torek <no****@torek.net> writes:
In article <di*********@news2.newsguy.com>, Chris Torek
<no****@torek.net> writes:
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 article <di*********@news4.newsguy.com>
Michael Wojcik <mw*****@newsguy.com> wrote:
In Sea, is {0} a valid initializer for any (complete) object type?


Presumably "no".
If so, the first rule is arguably violated; if not, I for one
wouldn't use it.


... perhaps Sea should allow empty
brackets as the "universal initializer":

complete_object_type var = {};


That seems reasonable.
(Out of curiosity, what is the referent for the pronoun "it" at
the end of the quote above? The language, or {0}?)


The language; I was feeling cranky, and I like having a universal
initializer.

--
Michael Wojcik mi************@microfocus.com

Memory, I realize, can be an unreliable thing; often it is heavily coloured
by the circumstances in which one remembers, and no doubt this applies to
certain of the recollections I have gathered here. -- Kazuo Ishiguro
Nov 15 '05 #42

This discussion thread is closed

Replies have been disabled for this discussion.