Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!yale!cmcl2!uupsi!sunic!dkuug!freja.diku.dk!skinfaxe.diku.dk!thorinn From: thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) Newsgroups: comp.std.c Subject: Re: X3J11 Pleasanton meeting summary Message-ID: <1990Oct18.222053.25253@diku.dk> Date: 18 Oct 90 22:20:53 GMT References: <13996@smoke.BRL.MIL> <1990Oct2.164709.23887@zoo.toronto.edu> <1990Oct3.162241.15245@watdragon.waterloo.edu> <3913@goanna.cs.rmit.oz.au> Sender: news@diku.dk (The Netnews System) Organization: Department Of Computer Science, University Of Copenhagen Lines: 74 ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: >> >> struct foo x; >> >> struct foo { int i; }; >> >> /* the above is strictly conforming; incomplete-type objects can >> >> be defined, so long as by the end of the translation unit the >> >> type becomes complete so that storage can then be allocated */ >I have some difficulty with the interpretation, though. >Surely it is possible to produce a fragment of C code where you need >to know the size *before* the end of the translation unit? > struct Erewhon a, b; > void do_we_have_to_wait_until_the_end_of_the_unit_for_this_too() > { > a = b; > } > /* megabytes of source code follow ... */ >I can see how to handle this; plant calls to a static void __assign_Erewhon() >function, and generate it as soon as you know the size. Or call a generic >function, picking up the size from a static const, and plant code at the end >to initialise that. But that could mean the difference between using a >single instruction (movc3, if size < 64k) or calling a procedure (size >). If your compiler uses a two-pass assembler for backend, it can allocate a symbol for the size and set it when the size becomes known. If it emits finished code a function at a time, it could refer to an absolute linker symbol for the size and define it later. If you have emitted code for ``small'' objects and they turn out to be ``large'', couldn't you just give an error (if your limit is 32K or greater)? Anyway, a modifiable lvalue designates an object that does not have an incomplete type (3.2.2.1), so the assignment is non-conforming. >It isn't quite so clear how to handle > void surely_this_cannot_wait_so_long() > { > struct Erewhon butler[20]; > ... > samuel(&butler[18]); > } >without some sort of runtime support that comes pretty close to being >alloca(). I don't think you have to handle that either. A clue was given in another posting. As the draft I have says (3.5 Semantics): "If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator, or by the end of its init-declarator if it has an initializer." and (3.1.2.2) "The following identifiers have no linkage: an identifier declared to be anything other than an object or function; an identifier declared to be a function parameter; an identifier declared to be an object inside a block without the storage-specifier _extern_." My conclusion: the only objects that can be declared with an incomplete type are statics with file scope and externs (with any scope). (I don't know if structure members are objects, but they're constrained (3.5.2.1) to have a complete type anyway. Likewise, array elements are described as having an object type (3.1.2.5).) So far as I can see, you can't do anything interesting with objects of incomplete type. Possibly the rule about ``not needing the size'' is unnecessary because other constraints prevent that need from arising at all; any examples to the contrary? (Note that I'm arguing from a draft --- I hope my reasoning's still valid by the ANS.) -- Lars Mathiesen, DIKU, U of Copenhagen, Denmark [uunet!]mcsun!diku!thorinn Institute of Datalogy -- we're scientists, not engineers. thorinn@diku.dk