[comp.lang.c] possible structure initialization bug

fnf@mcdsun.UUCP (Fred Fish) (08/11/87)

The following possible bug report was generated due in part to
failure to compile code from a compiler test suite.  I'd like
to solicit opinions on whether or not the code is valid pre-ANSI
C, valid ANSI C, or not valid C.  Note also that Harbison and Steele
go into a little more detail than the draft ANSI standard, and also
introduce the notion that the "shape" of the initializers should
match the "shape" of the object being initialized, which in this case
I would take to mean that a valid initializer would be of the form
"{{a,b},{c,d}}".

-Fred


/*
 *	Possible structure initialization bug (see comments below).
 *	Results from various compilers are:
 *
 *	GNU C compiler:		No complaint.
 *				bar.foo[0][0] = 1;
 *				bar.foo[0][1] = 2;
 *				bar.foo[1][0] = 3;
 *				bar.foo[1][1] = 4;
 *
 *	SUN 3.2 C compiler:	complains about '}' expected
 *	(pcc based)		bar.foo[0][0] = 1;
 *				bar.foo[0][1] = 2;
 *				bar.foo[1][0] = 0;
 *				bar.foo[1][1] = 0;
 *
 *	Motorola 68020 cc	complains about '}' expected
 *	(pcc based)		bar.foo[0][0] = 1;
 *				bar.foo[0][1] = 2;
 *				bar.foo[1][0] = 0;
 *				bar.foo[1][1] = 0;
 *
 *	Greenhills 68020 cc	complains about initializer too large
 *				no output file generated.
 *
 *	The draft ANSI C standard is quite specific about the
 *	behavior when there are too few initializers for an
 *	aggregate or subaggregate, but doesn't really address
 *	the reverse situation of too many initializers (that I could
 *	find anyway).  Section 3.5.6 has this to say:
 *
 *	"There shall be no more initializers in an initializer list than
 *	there are objects to be initialized."   Well, I see four objects
 *	to initialize and four initializers, so read on...
 *
 *	"... the initializer for an object that has aggregate type shall
 *	be a brace-enclosed list of initializers for the members of the
 *	aggregate, wirttin in increasing subscript or member order.  If the
 *	aggregate contains members that are aggregates, the rules apply
 *	recursively to the subaggregates.  If the initializer of a sub-
 *	aggregate begins with a left brace, the succeeding initializers
 *	initialize the members of the subaggregate.  Otherwise, only
 *	enough initializers from the list are taken to account for the
 *	members of the first subaggregate; any remaining initializers
 *	are left to initialize the next member of the subaggregate of
 *	which the current aggregate is a part."
 *
 */

struct {
    int foo[2][2];
} bar = {
    {1, 2, 3, 4}
};

main ()
{
    printf ("bar.foo[0][0] = %d\n", bar.foo[0][0]);
    printf ("bar.foo[0][1] = %d\n", bar.foo[0][1]);
    printf ("bar.foo[1][0] = %d\n", bar.foo[1][0]);
    printf ("bar.foo[1][1] = %d\n", bar.foo[1][1]);
}

-- 
= Drug tests; just say *NO*!
= Fred Fish  Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282  USA
= seismo!noao!mcdsun!fnf    (602) 438-3614

gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/12/87)

In article <352@mcdsun.UUCP> fnf@mcdsun.UUCP (Fred Fish) writes:
>I'd like to solicit opinions on whether or not the code is valid pre-ANSI
>C, valid ANSI C, or not valid C.
>struct {
>    int foo[2][2];
>} bar = {
>    {1, 2, 3, 4}
>};

It's obviously not valid C -- you have provided 4 initializers in
the list for the object bar.foo[0], but that object is an aggregate
that only has two elements, bar.foo[0][0] and bar.foo[0][1].

What was probably intended should be written:
	struct {
		int foo[2][2];
	} bar = {
		{1, 2},
		{3, 4},	/* comma optional */
	};

Note that many existing compilers are overly permissive on this,
and that the intent of ANSI C will be to provide sane semantics
for the use of EITHER fully-bracketed initializer lists OR
completely unbracketed lists, with consistent but not necessarily
sane rules for the intermediate cases -- which we hope nobody will
ever be so foolish as to use.

A couple of X3J11 meetings ago, Dave Prosser and I independently
worked through the rules for an incompletely-bracketed case, and
came up with the same answer, as well as a conviction that the
rules were complete and consistent.  One or two other people
agreed with us, and most of the rest seemed as bewildered by the
initializer bracketing rules as I recently was by the lvalueness
rules.

drew@geac.UUCP (Drew Sullivan) (08/13/87)

Microsoft C, version 4.0 took the program without complaint and returned:

bar.foo[0][0] = 1
bar.foo[0][1] = 2
bar.foo[1][0] = 3
bar.foo[1][1] = 4

-- Drew Sullivan <drew@lethe.uucp>

drw@cullvax.UUCP (Dale Worley) (08/13/87)

fnf@mcdsun.UUCP (Fred Fish) writes:
# [Is the following construction valid?]
# 
# struct {
#     int foo[2][2];
# } bar = {
#     {1, 2, 3, 4}
# };
# 
# [Notes that the initializer "{{1, 2}, {3, 4}}" is
# preferred for portability in pre-ANSI systems.]

# [The following is from 3.5.6 of the Draft:]
#  *	"... the initializer for an object that has aggregate type shall
#  *	be a brace-enclosed list of initializers for the members of the
#  *	aggregate, written in increasing subscript or member order.  If the
#  *	aggregate contains members that are aggregates, the rules apply
#  *	recursively to the subaggregates.  If the initializer of a sub-
#  *	aggregate begins with a left brace, the succeeding initializers
#  *	initialize the members of the subaggregate.  Otherwise, only
#  *	enough initializers from the list are taken to account for the
#  *	members of the first subaggregate; any remaining initializers
#  *	are left to initialize the next member of the subaggregate of
#  *	which the current aggregate is a part."

It seems to be that the last clause has a typo; it should read "...the
next member of the *aggregate* of which the current *subaggregate* is
a part".  Otherwise it doesn't make sense.

My reading is that if a subaggregate initializer (in this case, for
the two subordinate arrays) doesn't start off with a '{', then it just
draws the proper number of elements from the list and the remainder of
the list initializes elements of the top-level aggregate.

What you wrote should work, because you are initializing a "structure
with a field which is an array of arrays of integers".  The
initializers break down:

	object		initializer
	bar		{ { 1, 2, 3, 4 } }
	bar.foo		{ 1, 2, 3, 4 }

At this point, we invoke the "if the initializer for a subaggregate
does not begin with a left brace rule", and the elements bar.foo[*][*]
get initialized like you'd expect.

Dale
-- 
Dale Worley	Cullinet Software		ARPA: cullvax!drw@eddie.mit.edu
UUCP: ...!seismo!harvard!mit-eddie!cullvax!drw
OS/2: Yesterday's software tomorrow	    Nuclear war?  There goes my career!

gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/15/87)

In article <353@mcdsun.UUCP> fnf@mcdsun.UUCP (Fred Fish) writes:
>I should probably have noted in the original posting that the reason
>this question came up, what that there was similar code (with lots
>more dimensions and lots more brackets) in a commercial compiler test 
>suite that I am entangled in at the moment.  ...

Well, it sounds like the test suite is trying to test dark corners
of the language where it was never clear what was "right".  I know
of three commercial C compiler test suites, and they each try to
test a different "flavor" of C (one of them comes in a couple of
flavors).  Obviously, none of them can yet test against the ANSI
standard for C, which will be the most meaningful reference point
in the near future.

>...  Most of the problems appear to be generic pcc type bugs.

Certainly PCC (in its various versions) has had lots of bugs and
strange ideas what the language rules were.  Some test suites
actually check for conformance to PCC's idea of the language!
(K&R Appendix A is the other popular reference point.)

peter@sugar.UUCP (Peter da Silva) (08/16/87)

int x[2][2] = { 1, 2, 3, 4 };

I believe Ritchie's compiler (and other old 'C' compilers) treated nested
parentheses in aggregate initialisations as informative only, to be used
when ambiguities were found or subelements weren't fully initialised.

For example:

int x[2][2] = { 1, 2 } == { {1, 2}, {0, 0} };

	1 2
	0 0

int x[2][2] = { {1}, {2} } == { {1, 0} {2, 0} };

	1 0
	2 0
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)

michaud@decvax.UUCP (Jeff Michaud) (08/18/87)

	What you really want is:

	struct {
	   int foo[2][2];
	} xyz = {
	   1, 2, 3, 4
	};

	Notice only a depth of 1 on the {} nesting.

brianc@cognos.uucp (Brian Campbell) (08/19/87)

In article <352@mcdsun.UUCP> fnf@mcdsun.UUCP (Fred Fish) writes:
> [ question as to whether following is valid initialization ]
> struct {
>     int foo[2][2];
> } bar = {
>     {1, 2, 3, 4}
> };

   Is this really a *struct* initialization question, or a two-
dimensional array initialization question?  According to K&R (Sec. 5.7):

   "An array is initialized by a list of initializers in braces; each
   row of a two-dimensional array is initialized by a corresponding
   sub-list."
-- 
Brian Campbell          uucp: decvax!utzoo!dciem!nrcaer!cognos!brianc
Cognos Incorporated     mail: 3755 Riverside Drive, Ottawa, Ontario, K1G 3N3
(613) 738-1440          fido: sysop@163/8

fnf@mcdsun.uucp (Fred Fish) (08/20/87)

In article <6277@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <352@mcdsun.UUCP> fnf@mcdsun.UUCP (Fred Fish) writes:
>[..deleted..]
>What was probably intended should be written:
>[..deleted..]
>completely unbracketed lists, with consistent but not necessarily
>sane rules for the intermediate cases -- which we hope nobody will
>ever be so foolish as to use.

I should probably have noted in the original posting that the reason
this question came up, what that there was similar code (with lots
more dimensions and lots more brackets) in a commercial compiler test 
suite that I am entangled in at the moment.  Naturally, I cannot post
the relevant test code, but I believe my distillation of the code
that triggered a possible bug is correct.  It is obvious that the
compiler test suite is trying to test the bounds of the initialization
rules, as there are lots and lots of different permutations of
partially bracketed lists.  By the way, this same test suite has turned
up over a dozen bugs in the native Sun 3.2 C compiler and the Motorola
68020 C compiler and I've only just recently finished running the first
of many parts of the suite.  Most of the problems appear to be generic
pcc type bugs.

-Fred


-- 
= Drug tests; just say *NO*!
= Fred Fish  Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282  USA
= seismo!noao!mcdsun!fnf    (602) 438-3614

gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/23/87)

In article <1287@cognos.UUCP> brianc@cognos.UUCP (Brian Campbell) writes:
>   Is this really a *struct* initialization question, or a two-
>dimensional array initialization question?

According to current notions, it'a an AGGREGATE initialization question.