Path: utzoo!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!mcsun!ukc!dcl-cs!aber-cs!rupert!pcg From: pcg@rupert.cs.aber.ac.uk (Piercarlo Grandi) Newsgroups: comp.lang.c++ Subject: Re: g++ core dump from improper use of extern "C" Message-ID: Date: 15 Jan 90 13:44:18 GMT References: <1581@aber-cs.UUCP> <18157@umn-cs.CS.UMN.EDU> <25AFE9B7.14113@paris.ics.uci.edu> <25B0E7F7.6002@paris.ics.uci.edu> Sender: pcg@aber-cs.UUCP Organization: Coleg Prifysgol Cymru Lines: 93 In-reply-to: rfg@ics.uci.edu's message of 14 Jan 90 20:58:31 GMT In article <25B0E7F7.6002@paris.ics.uci.edu> rfg@ics.uci.edu (Ron Guilmette) writes: In article <25AFE9B7.14113@paris.ics.uci.edu> rfg@ics.uci.edu (Ron Guilmette) writes: >In article <18157@umn-cs.CS.UMN.EDU> mike@umn-cs.cs.umn.edu (Mike Haertel) writes: >> >>Just to be pedantic, this is not strictly true. It is OK to >>declare a pointer to an incomplete type, so this works *here*. >>But consider the following counterexample: >> >>/*1*/ struct b { int x; }; >>/*2*/ >>/*3*/ void foo() { >>/*4*/ struct b; >>/*5*/ struct a { struct b *b; } *a; >>/*6*/ struct b { struct a *a; } *b; >>/*7*/ >>/*8*/ b = a->b; >>/*9*/ } >> >>In this case, line 4 is necessary to make "struct b" an incomplete type. >>Otherwise, the "struct b *b" in line 5 would refer to the "struct b" >>declared on line 1... Well, not in C; in C line 4 is an empty declaration and the type used is the one defined on line 1 (see K&R version 1, "The ice is admittedly thin here" footnote). In C++ 2.0 line 4 does declare a new type, but only because of special casing: >Buzzzzzzzt! Sorry, no! But thanks for playing our game. Just for being >such a good sport you win a free copy of our home game, complete with the >new 2.0 Reference Manual. OK, before you folks send me 8 zillion letters telling me what a dumbs*** I am for having posted this, let me just say that I know already! The special case is this: in C++ a struct or class implies an automatic typedef; a typedef in theory does not declare a new type, but only names an existing one; so line 4 should just define a new typedef called 'b' for the type defined in line 1. This means that it is virtually impossible then to define mutually recursive types in an inner scope if *both* of them have the same name as one in an outer scope. It would also make for great hidden bugs. Try the following C program: typedef short t; static struct a {struct b *b; long l[1];} a; main() { { auto t t1; typedef double t; auto t t2; printf(" size t1 %u, size t2 %u\n",sizeof t1, sizeof t2); } { struct a; struct c {struct a *a; long l[2];} c; struct a {struct c *c; long l[3];} a; printf(" size a %u, size c %u, size c.a %u\n", sizeof a, sizeof c, sizeof *(c.a)); } return 0; } This should print, on your typical 32 bit byte oriented machine, something like 8 and 2 on the first line and 16, 12, 8 on the second line. NOTE: it will fail to compile on some ancient C compilers that erroneously handle a typedef like a #define, e.g. Sun's. Actually the problem is even more subtle, and has to do with the fact that certain classes of identifiers in C/C++ have global scope even if defined in an inner scope; struct/union/class names used to be such, if memory serves me right, and one could not redefine a name for one in an inner scope. C++, and C++ 2.0, complicates scope rules even further. I am not suprised then that in the new C++ 2.0 empty declarations have been special cased to imply the definition of a NEW type: Section 9.1 of the new 2.0 manual does indeed require the declaration of struct b in the example above. ... but this adds a new wart. Well, happy hacking! :-(. -- Piercarlo "Peter" Grandi | ARPA: pcg%cs.aber.ac.uk@nsfnet-relay.ac.uk Dept of CS, UCW Aberystwyth | UUCP: ...!mcvax!ukc!aber-cs!pcg Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk