[comp.std.c] X3J11 Pleasanton meeting summary

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/02/90)

Here is a summary of my personal idea of additional interpretations that
X3J11 came up with at the recent Pleasanton, CA meeting.  Note that these
should NOT be taken as official X3J11 responses to requests for
interpretation; those will be mailed directly to requestors and published
in official X3J11 documents.  I'm summarizing these simply as a "public
service" (also a trip report!), and I might have gotten some of the details
wrong.  I almost surely have omitted some decisions, due to incomplete notes.

Technical decisions:

	register union { int i; } u;
	&u.i;	/* constraint error, storage class inherited by members */

	size_t is defined merely as an aid to applications; the actual
	type is built into the compiler.

	"assignment expression" on p.54 l.32 refers to l.3, not l.5.

	p.63 "when the size ... is needed" means when needed by the rules
	in the STANDARD, not when needed by the implementation.

	typedef int array_t[];	/* incomplete type permitted */
	array_t a = { 1, 2 };	/* `a' has complete type (int a[2]) */
	array_t b = { 1, 2, 3 };/* `b' has complete type (int b[3]) */
	sizeof(array_t);	/* error; array_t type still incomplete */

	int a[4][5];
	a[1][7] = 0;	/* undefined behavior */

Dave Prosser (our Redactor) vigorously protested the above interpretation.

	The "first member" of a union to which an explicit initializer
	is assigned is the first NAMED member.

	Similarly, "every member" at the top of p.73 means every NAMED
	member.  (There would be no strictly conforming way to tell
	about the unnamed members anyway.)

	f2(void);	/* there are no parameters */
	f2(){}		/* compatible, there are no parameters */

	#define f(a) a*g
	#define g(a) f(a)
	f(2)(9)		/* involves "split hide sets" */
	/* expands to either of the following (intentionally undefined): */
	2*f(9)
	2*9*g

	void *p;
	&*p;	/* constraint violation; &void not allowed */

Note that AT&T would like the following to be permitted, but it isn't:
	extern void end;
	&end;
Frankly, I don't wish to support use of end/edata/etext at all, but if
it is necessary, these should be declared char, not void.  The linker has
to deal with these labels specially anyway.

	p.133 l.1 implies that the # flag takes precedence over the rule
	on p.134 that trailing zeros are removed for fprintf() %g format.

	When it is specified that a function "returns X and stores Y in
	errno", it does not mean that those actions occur in that order.

	For scanf("%5e",&f) with next available input sequence "1.2e+4xy",
	all relevant scan termination checks are to be applied for each
	successive character before inputting another character; thus a
	"matching failure" finally occurs after 5 characters are
	successfully examined for strtod() subject string expected-form
	acceptability, and the next unread character will be '4' ("e+" is
	NOT pushed back onto the input).

The above interpetation reflects more the agreed intent of previous
committee decisions than an unambiguous reading of the specification.

	p.69 l.22ff can be applied globally as needed, to fill in the
	"hole" in the specs for composite types involving functions with
	array parameter declarations.

	extern	struct s { struct s *p; } x;
		struct s { struct s *p; } x;
	/* are intended to be compatible types, although the rules as
	   given in the standard are technically infinitely recursive */

Pragmatic implementation techniques for enforcing the above are known;
however, other indeterminate situations could also arise.  The above is
an important example to get right, and probably any implementation method
that guarantees that would be acceptable for the other more complex cases.

	Although the composite type for an enum/integer_type combination
	depends on the implementation definition for enum, that is not
	considered a problem.

	enum x { a = sizeof(enum x) };	/* undefined behavior */

	setjmp() may be implemented as either a function OR a macro;
	the Rationale is incorrect.  (Very likely it merely failed to
	track a change in the draft standard at some point.)

	Appendix F.3.9 clearly states the intent with respect to whether
	the high bit of a plain "int" bit-field acts as a sign bit; it
	is implementation-defined to be the same as either "signed int"
	or "unsigned int".  Promotions are intended to be value-preserving
	throughout the standard.

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

	In 3.5.7 (across pp.72-73), "every member" must be taken to mean
	just the first (named) member when the object is a union.  The
	following is implicitly initialized with a null pointer constant
	accessible via "u.p":
		union { char *p; int i } u;

	p.63 l.27 is to be interpreted such that "prior to the declaration
	that defines the content" means "before the end of the declaration-
	specifiers".  The following is strictly conforming:
		struct t { struct t *x; } s[sizeof(struct t/*complete*/)];

	There was general sentiment that {} counts as a separate level
	when counting the nested levels of "control structure" that an
	implementation supports; however, no final decision was made yet.

	When it was said that the offset supplied to fseek() "shall be a
	value returned by an earlier call to ftell", we meant an earlier
	SUCCESSFUL call.  Similarly for fsetpos().

	Object sizes are always expressed in terms of number of bytes;
	the ISO/SC22/WG14 normative addendum should probably be consistent
	in either always spelling this out or always relying on one place
	where this is explained.

	strcmp()ing is done in terms of UNSIGNED chars, and p.35 l.24ff
	makes the conversion well-defined, so there is no technical
	problem with the strcmp()/strncmp() spec.

	strcmp()ing includes comparison of the terminating null byte,
	since 4.1.1 specifically includes it in the string argument,
	so the return value for the case where one string is a "prefix"
	of the other is well defined.

	strtok() is correctly specified as it stands; "first call in the
	sequence" is correct.

	It doesn't matter whether "physical source line" is taken to mean
	the input to, or the output from, translation phase 1, since only
	"logical source lines" are relevant in the rest of the standard.

	It was intentional that p.81 l.24 does not mention qualifiers on
	the function return type, so use of qualifiers results in undefined
	behavior.  P.65 l.24-25 is not relevant ("function type" is not the
	same as "function return type").

Administrative stuff:

	ANSI Std X3.159-1989 really has been printed, and it includes the
	Rationale; several copies were evident at the Pleasanton meeting.

I looked for copies at the Computer Literacy Bookshop in San Jose (Trimble
near First; one of the all-time great bookstores), but didn't find any.

	X3J11 members are all officially U.S. delegates to ISO WG14.

	Derek Jones was unanimously confirmed by X3J11 as the SC22
	"normative addendum" editor.

That seems to me to be simply a show of support, not anything official.

	Rex Jaeschke (our International Representative)  was instructed (?)
	to report that all non-boilerplate ANSI edits should be included
	into the draft ISO standard.

	ISO balloting is awaiting the Redactor's reformatting of the
	draft according to ISO guidelines, and if all goes well the same
	technical standard should be approved for ISO C as for ANSI C by
	early 1991.

	X3J11 recommended that the normative addendum NOT be submitted as
	several separate documents.

	X3J11 approved initiation of an "I-project" to work in conjunction
	with WG14 on the normative addendum.

	X3J11 supported the WG14 multibyte proposal (addendum), subject
	to further technical edits.

My particular concern is that no strictly conforming program by the rules
of the ANSI C standard become not strictly conforming to the extended ISO
standard.  The Japanese proposal currently infringes on the name space
guaranteed by ANSI C for use by strictly conforming programs; this can be
fixed without major adverse impact on the general proposal, and should be.

Incidentally, note how messy application programming is becoming due to
the adoption of the "visible multibyte behavior" model rather than a
transparent scheme such as proposed in X3J11/86-136.  I find it interesting
that one of the authors of "Software Tools", which showed how a clean model
can greatly simplify character-set programming, would have backed such a
messy alternative.  However, although there may be lessons to be learned,
we seem to be stuck with visible multibyte behavior now.

	Jim Brodie (our Chair) will submit a synchronization plan that
	proposes periodic joint meetings of WG14 and X3J11, track the
	ISO/SC22 rules, have X3J11 prepare the U.S. position on the
	normative addendum, and develop a plan for joint ANSI/ISO
	interpretations of the combined standard(s).

	Doug Gwyn will review X3T2 documents and prepare a recommendation
	whether or not X3J11 should establish an X3T2 liaison.

	Next X3J11 meeting is in Norwood, MA for 2.5 days, 6-8 Mar 1991.
	The meeting after that is expected to be in Europe as a joint
	WG14/X3J11 meeting in Dec 1991, otherwise at CBEMA in Washington,
	DC on 25-27 Sep 1991.  The following meeting is planned for Salt
	lake City, UT on 13-15 May 1992 and will be proposed to WG14 as
	a joint meeting.

	Response subgroups are required to submit their responses to Tom
	Plum (Vice Chair) by 9 Oct 1990, and documents for inclusion in
	the next X3J11 mailing must be received by 27 Oct 1990.  For the
	mailing after that, the deadline is 26 Jan 1991.  CBEMA is still
	handling the mailings at $80/year/person (members only).

REMINDER:  None of this is to be taken as any sort of official position
statement on behalf of X3J11, the U.S. Army, or any other organization.

henry@zoo.toronto.edu (Henry Spencer) (10/02/90)

In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>	p.63 "when the size ... is needed" means when needed by the rules
>	in the STANDARD, not when needed by the implementation.

Tsk tsk.  That just punts the issue.  As I pointed out in my submissions
to *both* second and third public reviews, there is *no* definition of
the phrase "when the size is needed", and no easy way to infer one.
*What* "rules in the STANDARD"???  The only place where the size is
unambiguously needed is sizeof.

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

Betcha there isn't a compiler on Earth that will accept that today.
Everyone I know read the size as being needed at the time of the declaration.
-- 
Imagine life with OS/360 the standard  | Henry Spencer at U of Toronto Zoology
operating system.  Now think about X.  |  henry@zoo.toronto.edu   utzoo!henry

henry@zoo.toronto.edu (Henry Spencer) (10/03/90)

I wrote:
>>	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 */
>
>Betcha there isn't a compiler on Earth that will accept that today.

Turns out that there are a few.  Bletch.  I have a hard time believing
that there would have been committee consensus on this.
-- 
Imagine life with OS/360 the standard  | Henry Spencer at U of Toronto Zoology
operating system.  Now think about X.  |  henry@zoo.toronto.edu   utzoo!henry

richard@aiai.ed.ac.uk (Richard Tobin) (10/03/90)

In article <1990Oct2.164709.23887@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>>	struct foo x;
>>	struct foo { int i; };

>Betcha there isn't a compiler on Earth that will accept that today.
>Everyone I know read the size as being needed at the time of the declaration.

This is what I too would have expected.  However, gcc seems to accept it
quite happily.

-- Richard

-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin

ccplumb@spurge.uwaterloo.ca (Colin Plumb) (10/03/90)

In article <1990Oct2.164709.23887@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) 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 */

> Betcha there isn't a compiler on Earth that will accept that today.
> Everyone I know read the size as being needed at the time of the declaration.

Taken.  $5.00?  Gcc 1.37.1 (VAX):

#include <stdio.h>
struct foo x;

struct foo {
	int i;
};

int main()
{
	x.i = 5;
	printf("++x.i = %d\n", ++x.i);
	return 0;
}

when run through gcc -ansi -pedantic -Wall produces a complaint about our
non-ANSI header files (printf returns an int, therefore it isn't defined),
and produces the expected output.
-- 
	-Colin

jejones@mcrware.UUCP (James Jones) (10/04/90)

In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) 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 */

Gee.  This seems to me to be rather inconsistent with other constraints
placed on C that appear to have as their justification allowing straight-
forward one-pass compilation.  Would it really be permissible to have

	struct foo;

	woof()
	{
		struct foo	x;

		/* ... */
	}

	/* ...eventually, at the end of the source file... */

	struct foo {
		int	i;
	};

for example?  Can one refer to fields in incomplete structures as long
as they occur in a complete declaration that appears by translation
unit's end?

	James Jones

msb@sq.sq.com (Mark Brader) (10/04/90)

A word of appreciation to Doug for posting this information.
One question:

> 	int a[4][5];
> 	a[1][7] = 0;	/* undefined behavior */
> Dave Prosser (our Redactor) vigorously protested the above interpretation.

My opinion is that the protest was right and the ruling wrong.
My question is whether rulings like this are valid for all time
(until the Standard is revised, that is) or whether they can be
reversed at a later meeting, if someone submits, say, a clearer
case for one point of view than was presented originally.

Doug?
-- 
Mark Brader, Toronto		"Mark is probably right about something,
utzoo!sq!msb, msb@sq.com	 but I forget what"	-- Rayan Zachariassen

This article is in the public domain.

seanf@sco.COM (Sean Fagan) (10/04/90)

In article <1990Oct2.164709.23887@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) 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 */
>Betcha there isn't a compiler on Earth that will accept that today.

You'd lose.  gcc will accept it.  pcc and msc, on the other hand, blow
chunks at it.

However, I agree with you.  It seems foolish to allow that declaration.
Is

	struct foo x[1024];
	int c;
	struct foo { unsigned char [32567]; };

supposed to work, as well?  What if it is part of a struct or union
definition?

-- 
-----------------+
Sean Eric Fagan  | "Never knock on Death's door:  ring the bell and 
seanf@sco.COM    |   run away!  Death really hates that!"
uunet!sco!seanf  |     -- Dr. Mike Stratford (Matt Frewer, "Doctor, Doctor")
(408) 458-1422   | Any opinions expressed are my own, not my employers'.

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/04/90)

In article <1990Oct3.184359.2348@sq.sq.com> msb@sq.sq.com (Mark Brader) writes:
>My question is whether rulings like this are valid for all time
>(until the Standard is revised, that is) or whether they can be
>reversed at a later meeting, if someone submits, say, a clearer
>case for one point of view than was presented originally.

So far as I have heard, there is nothing to prohibit somebody from
sending in a request for interpretation that is similar to a previous
one.  However, unless you make a very convincing case for a change
in interpretation, the committee would probably simply repeat their
earlier decision (which, after all, did result from substantial
discussion and debate before the vote was taken).  I can give the
argument for the majority position for this particular issue, if
you want to hear it; I was the one who presented the issue before
the committee (I still have the multi-colored viewfoil for it).

Note that X3J11 interpretation rulings are, strictly speaking, not
part of the official standard.  However, since some of them, this
one included, were in response to requests for clarification from
the editor of the "normative addendum" for the International
Standard, there IS a chance that such rulings might be incorporated
into the ISO C standard (via the normative addendum, not for the
initial standard, which last I heard is still technically identical
to the ANSI standard).

steve@taumet.com (Stephen Clamage) (10/05/90)

jejones@mcrware.UUCP (James Jones) writes:

>In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) 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 */

>Gee.  This seems to me to be rather inconsistent with other constraints
>placed on C that appear to have as their justification allowing straight-
>forward one-pass compilation.

I believe the statement above attributed to Doug is not quite correct.
The "struct foo x;" declaration uses an "incomplete type".
Section 3.5.2.3 says that an incomplete type "may be used only when
the size of an object of the specified type is not needed."

So if you had
	struct foo x;
	size_t bar() { return sizeof(x); }
	struct foo { int i; };
this would violate the constraint, as would
	struct foo x, y;
	void bar() { x = y; }
	struct foo { int i; };
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

ccplumb@spurge.uwaterloo.ca (Colin Plumb) (10/05/90)

In article <470@taumet.com> steve@taumet.com (Stephen Clamage) writes:
> I believe the statement above attributed to Doug is not quite correct.
> The "struct foo x;" declaration uses an "incomplete type".
> Section 3.5.2.3 says that an incomplete type "may be used only when
> the size of an object of the specified type is not needed."
>
> So if you had
>	struct foo x;
>	size_t bar() { return sizeof(x); }
>	struct foo { int i; };
> this would violate the constraint, as would
>	struct foo x, y;
>	void bar() { x = y; }
>	struct foo { int i; };

I have to agree with Henry, though, in saying that "needed" is hoplessly
vague.  Given an incomplete type Foo, here are the things I can imagine
doing with it:

extern Foo variable;
Foo variable;
{ Foo variable; ... }
Foo function(...);
Foo function(...){...}
extern Foo variable[];
Foo variable[];
sizeof(Foo);

Which are legal?

And the follwoing produce a type Bar on which the question can be
asked recursively...

typedef Foo Bar;
typedef Foo *Bar;
typedef Foo Bar(...);
typedef Type Bar(Foo,...);
typedef Foo Bar[ELEMS];
typedef struct {... Foo x; ...} Bar;
typedef union {... Foo x; ...} Bar;

For which of these is the size needed?
-- 
	-Colin

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (10/05/90)

In article <1990Oct3.162241.15245@watdragon.waterloo.edu>, ccplumb@spurge.uwaterloo.ca (Colin Plumb) writes:
> In article <1990Oct2.164709.23887@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) 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 */

> > Betcha there isn't a compiler on Earth that will accept that today.
> > Everyone I know read the size as being needed at the time of the declaration.

> Taken.  $5.00?  Gcc 1.37.1 (VAX):

I note from The Annotated C++ Reference Manual (S 7.1.1, p 99)
"The name of a class can be used in an extern declaration.  Such
a declaration, however, cannot be used before the class has been
defined.  For example,
	struct S;
	extern S a;		// this is legal [my note]
	extern S f();
	extern void g(S);
	void h()
	    {
		g(a);		// error: S undefined
		f();		// error: S undefined
	    }
"

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 >).
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().
-- 
Fear most of all to be in error.	-- Kierkegaard, quoting Socrates.

henry@zoo.toronto.edu (Henry Spencer) (10/06/90)

In article <470@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>Section 3.5.2.3 says that an incomplete type "may be used only when
>the size of an object of the specified type is not needed."
>
>So if you had
>	struct foo x;
>	size_t bar() { return sizeof(x); }
>	struct foo { int i; };
>this would violate the constraint, as would
>	struct foo x, y;
>	void bar() { x = y; }
>	struct foo { int i; };

Prove the second example.  By reference to the standard only, please.
It is not hard to construct an implementation which can deal with the
assignment without knowing the size at the time (e.g., by generating
a call to memcpy() which references a to-be-filled-in-later variable
for the size of the struct).  I can find nothing in the standard which
makes your second example violate this so-called "constraint".

As I've said earlier, the *only* place where that "constraint" appears
to operate, based strictly on the wording of the standard, is in
"sizeof".  Everywhere else, sufficient cleverness in the implementation
can avoid it, by postponing decisions.  The only reason that "sizeof"
is an exception is that the standard demands that its value be known
at compile time.

>Section 3.5.2.3 says that an incomplete type "may be used only when
>the size of an object of the specified type is not needed."

The trouble is that nothing in the standard, anywhere, ever, says
"the size of the object is needed for this construct".  One can only
infer that "needed" refers to "needed by the implementation", which
leaves the whole issue (apart from "sizeof") implementation-defined and
makes nonsense out of the committee's recent interpretation.
-- 
Imagine life with OS/360 the standard  | Henry Spencer at U of Toronto Zoology
operating system.  Now think about X.  |  henry@zoo.toronto.edu   utzoo!henry

henry@zoo.toronto.edu (Henry Spencer) (10/06/90)

In article <14008@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>... I can give the
>argument for the majority position for this particular issue, if
>you want to hear it; I was the one who presented the issue before
>the committee (I still have the multi-colored viewfoil for it).

I, for one, would be very interested to hear what the committee thinks
the standard says about where "the size is needed".  I can't find any
place where the standard says anything about it whatsoever.
-- 
Imagine life with OS/360 the standard  | Henry Spencer at U of Toronto Zoology
operating system.  Now think about X.  |  henry@zoo.toronto.edu   utzoo!henry

daniels@ogicse.ogi.edu (Scott David Daniels) (10/06/90)

In article <1990Oct5.173314.28454@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>In article <470@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>>So if you had
>>  struct foo x; size_t bar() { return sizeof(x); } struct foo { int i; };
>>this would violate the constraint, as would
>>  struct foo x, y; void bar() { x = y; } struct foo { int i; };
>...It is not hard to construct an implementation which can deal with the
>assignment without knowing the size at the time (e.g., by generating
>a call to memcpy() which references a to-be-filled-in-later variable
>for the size of the struct).  I can find nothing in the standard which
>makes your second example violate this so-called "constraint"...

However, the preceding example is really no different.  If we presume the
fortuitous ``to-be-filled-in-later size variable,'' the return statement 
of the preceding example may load the return value register (or whatever 
convention the compiler prefers for results) from the same variable.  I
am not trying to pick on Henry Spencer.  I am just trying to make the
point that the committee's position is on a very slippery slope.  Since 
sizeof cannot be used to control preprocessing, I don't see where any 
special implementation difficulty is associated exclusively with sizeof.

Instead of choosing between two poor   | Scott Daniels at Oregon Graduate Inst.
    graphics standards, we get X       | daniels@cse.ogi.edu    ogicse!daniels

henry@zoo.toronto.edu (Henry Spencer) (10/06/90)

In article <12672@ogicse.ogi.edu> daniels@ogicse.ogi.edu (Scott David Daniels) writes:
>However, the preceding example is really no different.  If we presume the
>fortuitous ``to-be-filled-in-later size variable,'' the return statement 
>of the preceding example may load the return value register (or whatever 
>convention the compiler prefers for results) from the same variable...

Not unless you're willing to work hard at fudging a number of other things.
ANSI C does insist that the result of sizeof be a compile-time number, and
so it is legitimate to use a sizeof in (e.g.) dimensioning another array.
You can postpone everything to runtime if you really work at it, as witness
the existence of C interpreters, but in a traditional compiled approach,
you really do have to evaluate sizeof at compile time to type-check things
like:

	char *p = sizeof(a) - sizeof(b);

which is legal if and only if the two sizeofs have the same value!
-- 
Imagine life with OS/360 the standard  | Henry Spencer at U of Toronto Zoology
operating system.  Now think about X.  |  henry@zoo.toronto.edu   utzoo!henry

peter@ficc.ferranti.com (Peter da Silva) (10/07/90)

In article <1990Oct4.233557.28571@watdragon.waterloo.edu> ccplumb@spurge.uwaterloo.ca (Colin Plumb) writes:
> I have to agree with Henry, though, in saying that "needed" is hoplessly
> vague.  Given an incomplete type Foo, here are the things I can imagine
> doing with it:

> extern Foo variable;
...

Also:

extern Foo *variable;
Foo *variable;
{ Foo *variable; }
Foo *function(...);
Foo *function(...){...}
extern Foo *variable[];
Foo *variable[];
sizeof(Foo *);

All of which should probably be legal... unless pointers to structures
can vary in size, or you dereference !variable! or the return value of
!function!. The latter two can be checked out, but how about varying
size pointers to structures (eg, !struct {char c};! having the same align
restrictions as !char! and requiring a longer pointer than !int *!)?
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/08/90)

In article <1990Oct3.184359.2348@sq.sq.com> msb@sq.sq.com (Mark Brader) writes:
> > 	int a[4][5];
> > 	a[1][7] = 0;	/* undefined behavior */
> > Dave Prosser (our Redactor) vigorously protested the above interpretation.
> My opinion is that the protest was right and the ruling wrong.

On what basis? If I declare char x[100][3], for example, the compiler
might want to allocate an extra byte for each element of x. Isn't this
allowed by the standard?

---Dan

chris@mimsy.umd.edu (Chris Torek) (10/08/90)

In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn)
posts a number of interpretations, including:
>	For scanf("%5e",&f) with next available input sequence "1.2e+4xy",
>	all relevant scan termination checks are to be applied for each
>	successive character before inputting another character; thus a
>	"matching failure" finally occurs after 5 characters are
>	successfully examined for strtod() subject string expected-form
>	acceptability, and the next unread character will be '4' ("e+" is
>	NOT pushed back onto the input).

A `matching failure'?  In other words, such a scanf() call would return 0,
not 1?  `e+' is lost?  Pity, after all that work I went through to make it
right.  :-)

Seriously, I think it is much better for the library to scan the number
as `1.2' and leave the `e+4xy' unread.  This turns out not to be too
difficult.

(I would have to check my copy of the last draft to verify the words I
use above, but I am here and it is not....)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/08/90)

In article <1737:Oct803:02:5890@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>In article <1990Oct3.184359.2348@sq.sq.com> msb@sq.sq.com (Mark Brader) writes:
>> > 	int a[4][5];
>> > 	a[1][7] = 0;	/* undefined behavior */
>> > Dave Prosser (our Redactor) vigorously protested the above interpretation.
>> My opinion is that the protest was right and the ruling wrong.
>On what basis? If I declare char x[100][3], for example, the compiler
>might want to allocate an extra byte for each element of x. Isn't this
>allowed by the standard?

Okay, I guess there is some point in summarizing the X3J11 discussion about
this issue.

Let's first of all give names to specific relevant types:
	typedef int	cell;	/* could be any object type, not just "int" */
	typedef cell	row[5];
	typedef row	matrix[4];
Then the largest object involved is
	matrix	a;		/* same as int a[4][5]; */
There are other objects that can readily be identified here;
	a[1];			/* denotes a row object */
	a[1][4];		/* correctly denotes a cell object */

X3J11 seemed to agree that there are sufficient constraints in the
standard that one can assert the following:
	assert(sizeof a == 4*sizeof a[1] && sizeof a == 4*5*sizeof a[1][4]);
In other words, the size of an array element INCLUDES any padding necessary
for adjacent elements to abut cleanly, and there is no additional padding
included in an array object.  Thus, every implementation COULD choose to
give a[1][7] a well-defined meaning; alignment and padding are not issues.

The actual issue is, what really constitutes an array object.  Note that
in the declaration grammar, for example in 3.5.4.2, an array HAS only one
level of aggregation.  There is not officially any such thing as a "multi-
dimensional array" in C, only arrays of arrays.  (The description in such
terms in 3.3.2.1 Semantics should be considered informal, English, usage
of "multidimensional" for purposes of exposition, not the implicit
introduction of a technical language construct.  In fact, you have to take
that description as referring to the more precise notion of arrays of
arrays in order for the description to make any sense.)

3.3.2.1 (p.40) and 3.3.6 (p.48) state quite clearly, in the majority view
of X3J11, that subscripting an array in effect removes ONE level of a
multi-level aggregation.  The wording on p.48 is, for example:  "When an
expression that has integral type is added to or subtracted from a pointer,
the result has the type of the pointer operand.  If the pointer operand
points to an element of an array object, and the array is large enough,
the result points to an element offset from the original element such that
the difference of the subscripts ...  In other words, if the expression P
points to the i-th element of an array object, the expressions ... point
to, respectively, the i+n-th and i-nth elements of the array object,
provided they exist.  ...  If both the pointer operand and the result
point to elements of the same array object, ... the evaluation shall not
produce an overflow; otherwise, the behavior is undefined.  Unless both
the pointer operand and the result point to elements of the same array
object, ... the behavior is undefined if the result is used as an operand
of the unary * operator."  (Note that 3.3.2.1 in effect rewrites E1[E2] as
(*(E1+(E2))) (they are "identical"), so unary * is applied in our example.)

The above should prepare you to understand the committee's response:

	For an array of arrays, the permitted pointer arithmetic in
	Standard section 3.3.6 Semantics (p. 48, ll. 12-40) is to be
	understood by interpreting the use of the word "object" as
	denoting the specific object determined directly by the pointer's
	type and value, NOT other objects related to that one by
	contiguity. For example, the following code has undefined behavior:

		int a[4][5];
		a[1][7] = 0;	/* undefined */

	Some conforming implementations may chose to diagnose an "array
	bounds violation", while others may chose to interpret such
	attempted accesses successfully with the "obvious" extended
	semantics.

Note that even such a subterfuge as the following would not be strictly
conforming:

	void func( int *p ) { p[7] = 0; }
	void main( void ) { int a[4][5]; func( a[1] ); return 0; }

This isn't much of a practical problem, at least not in most code that
I recall having written, because most often multidimensional "matrices"
are actually allocated as 1-dimensional arrays of the desired "cell"
type, accessed later via a pointer to one of the cells (normally the
first), and p.48 supports that usage.  Indeed, as NCEG considers ways to
add more useful notions of arrays and subarrays to the C language, such
tight constraints on what are and are not permissible operations on such
objects may well prove to be essential, at least from the point of view
of implementors of C compilers on "vector" architectures.

What is missing in the standard that would be required for such punning
to be strictly conforming is some sort of guarantee that an array of
arrays of T is also in some contexts considered an array of T itself.
As it stands, the rigorous type structure shines through too plainly.
Some X3J11 members actually want precisely that, arguing that their
implementations warn about array bounds violations and that their
customers have indicated that they strongly desire that feature.

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/08/90)

In article <26889@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:
>Seriously, I think it is much better for the library to scan the number
>as `1.2' and leave the `e+4xy' unread.

That was my opinion, too, but X3J11 decided otherwise.
I think the main motivation was the abhorrence many members have to
the idea that when scanning an input stream they might have to "push
back" several characters.

rns@se-sd.SanDiego.NCR.COM (Rick Schubert) (10/09/90)

In <26889@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes:

>In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn)
>posts a number of interpretations, including:
>>	For scanf("%5e",&f) with next available input sequence "1.2e+4xy",
[produces a "matching failure" and the next unread character will be '4']

>A `matching failure'?  In other words, such a scanf() call would return 0,
>not 1?  `e+' is lost?

>Seriously, I think it is much better for the library to scan the number
>as `1.2' and leave the `e+4xy' unread.  This turns out not to be too
>difficult.

Note that at this point, the role of X3J11 is to interpret what the Standard
says, not what would be nice.  We are not even allowed to say "but we had
meant to say ..." if the Standard is unambiguous.  If there is an
ambiguity, we can resolve it based on demonstrated intent.

I don't know if the given interpretation is consistent with our original
intent.  If it is, I suspect that we made that decision to simplify the
specification of `scanf'.

-- Rick Schubert (rns@se-sd.sandiego.NCR.COM)

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/09/90)

In article <14049@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>	void main( void ) { int a[4][5]; func( a[1] ); return 0; }

I of course meant:
	int main( void ) { int a[4][5]; func( a[1] ); return 0; }

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/09/90)

In article <14049@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <1737:Oct803:02:5890@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> >In article <1990Oct3.184359.2348@sq.sq.com> msb@sq.sq.com (Mark Brader) writes:
> >>> 	int a[4][5];
> >>> 	a[1][7] = 0;	/* undefined behavior */
> >>> Dave Prosser (our Redactor) vigorously protested the above interpretation.
> >>My opinion is that the protest was right and the ruling wrong.
> >On what basis? If I declare char x[100][3], for example, the compiler
> >might want to allocate an extra byte for each element of x. Isn't this
> >allowed by the standard?
> Okay, I guess there is some point in summarizing the X3J11 discussion about
> this issue.
  [ int a[4][5] ]
> X3J11 seemed to agree that there are sufficient constraints in the
> standard that one can assert the following:
> 	assert(sizeof a == 4*sizeof a[1] && sizeof a == 4*5*sizeof a[1][4]);
> In other words, the size of an array element INCLUDES any padding necessary
> for adjacent elements to abut cleanly, and there is no additional padding
> included in an array object.  Thus, every implementation COULD choose to
> give a[1][7] a well-defined meaning; alignment and padding are not issues.

Hey! You're skipping a few steps there!

Let me switch back to my example, because it's more realistic.

In char x[100][3], suppose the compiler allocates 4 bytes for each x[i],
to speed access and allow word copies/comparisons. Now

  x is of type char [100][3],    sizeof(x) is 400
  x[1] is of type char [3],      sizeof(x[1]) is 4
  x[1][2] is of type char,       sizeof(x[1][2]) is 1

Now explain to me why this is illegal. Can sizeof(x[1]) be 4, as I think
it should be? Where is it required that the size of an array be the
number of elements in it times the size of an element?

If this is illegal, ANSI has cut out a very useful optimization.

If this is legal, then the ``obvious'' extension that would allow
x[1][7] is simply wrong. Not just nonconforming, but wrong.

Somebody has to lose here, and I think it should be the x[1][7] folks.

---Dan

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/09/90)

In article <7944:Oct906:02:0690@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>  x is of type char [100][3],    sizeof(x) is 400

Not permitted.  sizeof x is required to be 300.

>Where is it required that the size of an array be the
>number of elements in it times the size of an element?

3.3.3.4 uses the property in an example, and I think one can read 3.1.2.5
as specifying that an array type decribes ONLY the contiguous objects of
which it consists.  3.3.3.4 Semantics second paragraph lends further
support to this, since struct/union padding is mentioned but no mention
is made of array padding (which isn't supposed to exist).  I think you
can also extract the same conclusion from 3.3.2.1 Semantics.

If it bothers you, send in a request for interpretation.

paul@u02.svl.cdc.com (Paul Kohlmiller) (10/10/90)

I want to thank Doug for that description of the over-indexed array problem. I
did not take as many notes as Doug did at that meeting but there are two more
points to be made in favor of the committee's decision and one in favor of
Dave P.'s position. First, my understanding of what Bill Plauger said is that
the compiler might be forced to fully pack a multidimensional array but it is
not forced to do the correct pointer arithmetic when array are overindexed.
Secondly, many people have pointed out that it is still possible to take the
address of the array and do some "naked" arithmetic on it. The problem with
overindexing is that it is "as if" the address was taken in a quite way.
I think Dave feels that the standard supports his position but that this 
kind of overindexing is needed to allow for (excuse me in advance for
introducing this word) polymorphic arrays. (Arrays that can change shape.)
I think the real solution for polymorphic arrays lies within NCEG's 
discussion of variable dimensioned arrays.

--
     // Paul H. Kohlmiller           //  "Cybers, Macs and Mips"         //
     // Control Data Corporation     // Internet: paul@u02.svl.cdc.com   //
     // All comments are strictly    // America Online: Paul CDC         //
     // my own.                      // Compuserve: 71170,2064           // 

msb@sq.sq.com (Mark Brader) (10/12/90)

To Doug Gwyn's summary:
> 	int a[4][5];
> 	a[1][7] = 0;	/* undefined behavior */
> Dave Prosser (our Redactor) vigorously protested ...

I wrote:
@ My opinion is that the protest was right and the ruling wrong.

Doug then posts a longer form of the ruling:
: For an array of arrays, the permitted pointer arithmetic in
: Standard section 3.3.6 Semantics (p. 48, ll. 12-40) is to be
: understood by interpreting the use of the word "object" as
: denoting the specific object determined directly by the pointer's
: type and value, NOT other objects related to that one by contiguity.

I now see that this is right, I was wrong, and it is undefined behavior.
But this leads to a problem, which I'll get to in a moment.

First, I should explain my error.  In reply to Karl Heuer's comment:
! I presume that this ruling (if upheld) also means that strictly conforming
! programs may not use extensible structs via the usual overmalloc hack?

Alan Rosenthal writes:
| Alternatively, (int (*)[5])malloc(4 * 5 * sizeof(int)) may be deemed to
| create an object viewable as being 20 ints even though int a[4][5] does
| not, in which case the overmalloc hack would still be fine (though
| blecherous).

And I agree with this also.  This was in fact the source of my original
confusion: I had previously examined the wording carefully to ensure that
the "overmalloc hack" was legal, remembered the conclusion, and forgotten
the reasoning behind it.  I then assumed that as I knew the conclusion
I didn't need to go back to the Standard and see the actual wording.
Stupid.


Now the problem.  Doug also notes:
> Note that even such a subterfuge as the following would not be strictly
> conforming:
> 	void func( int *p ) { p[7] = 0; }
> 	int main( void ) { int a[4][5]; func( a[1] ); return 0; }

And I agree with this also.  p points to the element a[1][0] in the array
a[1], and there is no element [7] in that array, so it's undefined.
But what if func was written as follows?

	void func (void *p) {int *ip = p; ip[7] = 0; }

Does ip also point to the element a[1][0] in the array a[1], and is
this therefore still non-conforming?  If so... can memcpy() really
be implemented in ANSI C, and used to copy arbitrary objects?

-- 
Mark Brader				"It's easier to deal with 'opposite
SoftQuad Inc., Toronto			 numbers' when you know you cannot
utzoo!sq!msb, msb@sq.com		 trust them."		-- Chess

This article is in the public domain.

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/12/90)

In article <1990Oct11.203338.16419@sq.sq.com> msb@sq.sq.com (Mark Brader) writes:
>But what if func was written as follows?
>	void func (void *p) {int *ip = p; ip[7] = 0; }
>Does ip also point to the element a[1][0] in the array a[1],

Yes.  The implied simple assignments to and from void* do not adversely
affect the value of the int*.  The conversion from int[] to int* that
occurred on the function call resulted in a pointer to a[1][0], so the
value in "ip" must point there also.

>and is this therefore still non-conforming?

The interesting aspect of the question is whether the underlying shape
of a[1] is still in force.  In practically all C implementations, of
course, such detailed type information would have been "scraped off"
by assignment through the void* knothole.  Taking the standard as a
whole into account, specifically malloc()'s role, I would say that the
clear intent of X3J11 was that the additional shape information is
expected to have been scraped off.

The other important aspect is whether or not 3.3.6 requires that ip[7]
then work.  By the previous argumentation, I would say that it is not
required to work, i.e. that the code is still not strictly conforming.
I would be quite surprised, however, to learn of a real implementation
that would take the necessary pains to make this usage fail.

>If so... can memcpy() really be implemented in ANSI C, and used to
>copy arbitrary objects?

Certainly memcpy() can be used to copy arbitrary objects in any
conforming implementation.  What you're really asking is whether a
strictly conforming implementation of memcpy() is possible.  I think
the conclusion is that it is not, but that a conforming (but not
strictly conforming) implementation would be portable in practice.
Remember that there is no requirement on the internal structure of an
implementation, so long as it provides the specified functionality and
obeys the other constraints (such as not infringing on the application
name space).  Undoubtedly, many memcpy() implementations will be done
via assembly language, not coded in any flavor of C.

jejones@mcrware.UUCP (James Jones) (10/17/90)

In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) 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 */

Sorry to bring this one up again, but I have something more than handwaving
to bring to the matter this time. :-)

If this is the current interpretation, then it is not consistent with the
"Semantics" portion of section 3.5 (lines 30-31, p.70), which states

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

So...does this reflect an official change in the standard?

	James Jones

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/18/90)

In article <3427@mcrware.UUCP> jejones@mcrware.UUCP (James Jones) writes:
-In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) 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 */
-If this is the current interpretation, then it is not consistent with the
-"Semantics" portion of section 3.5 (lines 30-31, p.70), which states

Where did you get your copy of the Standard?  Your page numbers don't
agree with mine.

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

I don't know why you think that this would apply.  The object "x" in
my example has external linkage.

-So...does this reflect an official change in the standard?

Of course not.  X3J11 is not in a position to change the standard now.

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/18/90)

In article <14061@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <7944:Oct906:02:0690@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> >  x is of type char [100][3],    sizeof(x) is 400
> Not permitted.  sizeof x is required to be 300.

It's a shame that a useful optimization is thereby prohibited. I just
posted a proposal to alt.lang.cfutures under the title ``array slicing''
that would let the programmer explicitly declare padding. In the
meantime, is there any portable way to get around this restriction?

---Dan

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/18/90)

In article <14005:Oct1801:26:5890@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>In article <14061@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>> In article <7944:Oct906:02:0690@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>> >  x is of type char [100][3],    sizeof(x) is 400
>> Not permitted.  sizeof x is required to be 300.
>... is there any portable way to get around this restriction?

What on earth are you talking about?  It's a restriction on the
implementation, not on a program.  It actually guarantees MORE
semantics that portable programs can exploit.

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/19/90)

In article <14181@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <14005:Oct1801:26:5890@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> >In article <14061@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> >> In article <7944:Oct906:02:0690@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> >> >  x is of type char [100][3],    sizeof(x) is 400
> >> Not permitted.  sizeof x is required to be 300.
> >... is there any portable way to get around this restriction?
> What on earth are you talking about?  It's a restriction on the
> implementation, not on a program.

Exactly. I want to give away some rights, and let the compiler do a
better job by allocating an extra byte for each element of x. In other
words, I want to get around this restriction.

What I'm really trying to ask is whether my only choice is to count
bytes manually, assume fixed type sizes, and declare the right number of
padding characters by hand. I'd rather let the compiler choose padding
for me---it usually does a better job.

---Dan

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/19/90)

In article <21360:Oct1820:21:0490@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>What I'm really trying to ask is whether my only choice is to count
>bytes manually, assume fixed type sizes, and declare the right number of
>padding characters by hand. I'd rather let the compiler choose padding
>for me---it usually does a better job.

I don't see why you should even be thinking along these lines.  Surely
the compiler is going to generate reasonable code without your assistance.

thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) (10/19/90)

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

diamond@tkou02.enet.dec.com (diamond@tkovoa) (10/19/90)

In article <3427@mcrware.UUCP> jejones@mcrware.UUCP (James Jones) writes:
>In article <13996@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) 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 */
>If this is the current interpretation, then it is not consistent with the
>"Semantics" portion of section 3.5 (lines 30-31, p.70), which states
>"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."

If this declaration of x is not inside a function or struct, and if no
other declaration of the same x is presently visible, then this declaration
gives x external linkage.  Presumably this has been the situation so far
in this discussion.

However, if this declaration ("struct foo x;") is inside a function
(possibly inside a nested block), or inside a declaration of another
struct, then this x (auto or struct member) has no linkage.  Therefore
it seems that Mr. Jones has proven the illegality of:
  struct foo;
  func() { struct foo x; }
  struct foo { int i; }
likely to the relief of many compiler writers.
-- 
Norman Diamond, Nihon DEC    diamond@tkov50.enet.dec.com
                                    (tkou02 is scheduled for demolition)
We steer like a sports car:  I use opinions; the company uses the rack.