Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Braced initializers (again)

8 views
Skip to first unread message

Ronald Guilmette

unread,
May 19, 1990, 3:42:31 AM5/19/90
to
I've still got real trouble trying to figure out section 3.5.7 of the ANSI
standard.

To make matters worse, checking out examples against numerous C compilers
does help matters much.

Consider the following code:

struct struct_0 {
int a;
int b;
};

struct struct_0 array_0[] = { { 1 }, 2, { 3 } };
struct struct_0 array_1[] = { { { 1 } }, 2 };
struct struct_0 array_2[] = { { { 1 } } };
struct struct_0 array_3[] = { { { 1 }, 2 }, 3 };
struct struct_0 array_4[] = { 1, { 2 } };

Trying to compile this code, I get the following variety of results from
various compilers:

GreenHills/386: all initializations are illegal
AT&T Cfront C++ translator: all initializations are illegal
GNU GCC: all initializations are legal
PCC/386: all initializations are legal
Sequent Symmetry cc: array_1 and array_3 initializations are illegal
Sun Sparc (SunOS 4.0) cc: array_1 and array_3 initializations are illegal

Anybody know who is right?

I'd also like to know what is supposed to happen in cases such as:

int array[2] = { 1, 2, 3 };

In other words, is the presence of extra initializers supposed to be ignored,
or should this be an error?

// Ron Guilmette (r...@ics.uci.edu)
// C++ Entomologist
// Motto: If it sticks, force it. If it breaks, it needed replacing anyway.

Henry Spencer

unread,
May 19, 1990, 6:41:25 PM5/19/90
to
In article <2654F8E...@paris.ics.uci.edu> r...@paris.ics.uci.edu (Ronald Guilmette) writes:
>To make matters worse, checking out examples against numerous C compilers
>does help matters much.

Complex initializer lists is an area where botched implementations are
common; checking examples against compilers is not likely to help much.

> struct struct_0 {
> int a;
> int b;
> };
>
> struct struct_0 array_0[] = { { 1 }, 2, { 3 } };

Looks okay to me, but probably doesn't do what you want. {1} initializes
the first struct, and the remaining two items initialize the second (an
initializer for a scalar can be enclosed in braces). Cautious compilers
should complain. Equivalent to { { 1, 0 }, { 2, 3 } }.

> struct struct_0 array_1[] = { { { 1 } }, 2 };

Equivalent to { { 1, 0 }, { 2, 0 } }. See above note on scalar initializers.
Cautious compilers should complain.

> struct struct_0 array_2[] = { { { 1 } } };

Equivalent to { { 1, 0 } }. Cautious compilers should complain.

> struct struct_0 array_3[] = { { { 1 }, 2 }, 3 };

E.t. { { 1, 2 }, { 3, 0 } }. C.c.s.c.

> struct struct_0 array_4[] = { 1, { 2 } };

E.t. { { 1, 2 } }. C.c.s.c.

>I'd also like to know what is supposed to happen in cases such as:
>
> int array[2] = { 1, 2, 3 };

3.5.7, "Constraints": "There shall be no more initializers in an initializer
list than there are objects to be initialized." This is an error.
--
Life is too short to spend | Henry Spencer at U of Toronto Zoology
debugging Intel parts. -Van J.| uunet!attcan!utzoo!henry he...@zoo.toronto.edu

Doug Gwyn

unread,
May 19, 1990, 10:38:15 PM5/19/90
to
In article <2654F8E...@paris.ics.uci.edu> r...@paris.ics.uci.edu (Ronald Guilmette) writes:
> struct struct_0 {
> int a;
> int b;
> };
> struct struct_0 array_0[] = { { 1 }, 2, { 3 } };
array_0[0].a = 1; array_0[1].a = 2; array0_[1].b = XXX;

> struct struct_0 array_1[] = { { { 1 } }, 2 };
array_1[0].a = XXX; array_1[1].a = 2;

> struct struct_0 array_2[] = { { { 1 } } };
array_2[0].a = XXX;

> struct struct_0 array_3[] = { { { 1 }, 2 }, 3 };
array_3[0].a = XXX; array_3[0].b = 2; array_3[1].a = 3;

> struct struct_0 array_4[] = { 1, { 2 } };
array_4[0].a = 1; array_4[0].b = XXX;

> GreenHills/386: all initializations are illegal
> AT&T Cfront C++ translator: all initializations are illegal
> GNU GCC: all initializations are legal
> PCC/386: all initializations are legal
> Sequent Symmetry cc: array_1 and array_3 initializations are illegal
> Sun Sparc (SunOS 4.0) cc: array_1 and array_3 initializations are illegal

>Anybody know who is right?

They all are. Since the XXX misusages ({} around inner scalar
initializers) do not violate 3.5.7 Syntax or Constraints, just
Semantics, a diagnostic is not required, but it is allowed.
Support for this usage is not required but is a permitted extension.

(You probably thought that the optional {} around scalar
initializers were also allowed at inner levels, not just outer.
I admit this is not as clear as it should be.)

>I'd also like to know what is supposed to happen in cases such as:
> int array[2] = { 1, 2, 3 };

This violates the first Constraint of 3.5.7, and must be diagnosed.

Henry Spencer

unread,
May 20, 1990, 2:04:51 AM5/20/90
to
In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>(You probably thought that the optional {} around scalar
>initializers were also allowed at inner levels, not just outer.
>I admit this is not as clear as it should be.)

I'd say it's quite clear, and the meaning is the opposite of what you
think it is. The standard *as written* clearly allows it, unless this
was revised between the Oct 88 draft and the final standard. It's a
bit late to say this wasn't what was intended.

Doug Gwyn

unread,
May 20, 1990, 3:59:30 PM5/20/90
to
In article <1990May20.0...@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>>(You probably thought that the optional {} around scalar
>>initializers were also allowed at inner levels, not just outer.
>>I admit this is not as clear as it should be.)
>I'd say it's quite clear, and the meaning is the opposite of what you
>think it is. The standard *as written* clearly allows it, unless this
>was revised between the Oct 88 draft and the final standard. It's a
>bit late to say this wasn't what was intended.

Actually I can read the specification both ways without much stretch
of the imagination. I would urge that this be sent in as an official
request for interpretation. The issue can be simplified to whether
or not the following is okay for inclusion in a strictly conforming
program:

struct { int i , j ; } s = { { 1 } , 2 } ;

If so, then the following is presumably also okay:

int i = { { { { 3 } } } } ;

Henry Spencer

unread,
May 22, 1990, 3:25:40 PM5/22/90
to
In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>>>(You probably thought that the optional {} around scalar
>>>initializers were also allowed at inner levels, not just outer...
>>... The standard *as written* clearly allows it...

>Actually I can read the specification both ways without much stretch
>of the imagination...

Can you explain how you can read it to forbid the {}?

"...the initializer for an object that has aggregate type shall be a
brace-enclosed list of initializers for the members of the aggregate..."
The discussion of aggregate initializers talks at length about how you
build aggregate initializers from initializers for the aggregate's
members, but says nothing about the form of initializers for members
which are scalars. The entire discussion of scalar initializers is:

"The initializer for a scalar shall be a single expression,
optionally enclosed in braces. The initial value of the object
is that of the expression; the same type constraints and
conversions as for simple assignment apply."

If this is meant to apply only to scalars which are not members of
aggregates, (a) this is not stated, and (b) there is no definition
of how scalar members *are* initialized. The only rational conclusion,
based on the text and not on preconceived ideas from elsewhere, is that
this entire paragraph applies to scalar initializers whether or not they
are part of aggregate initializers.

Unless the wording has changed since the Oct 88 draft, I see no way of
reading it to forbid the braces.

>I would urge that this be sent in as an official

>request for interpretation...

I'm not sure why; the wording seems clear and specific.

Doug Gwyn

unread,
May 23, 1990, 4:31:06 AM5/23/90
to
In article <1990May22.1...@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>>>>(You probably thought that the optional {} around scalar
>>>>initializers were also allowed at inner levels, not just outer...
>>>... The standard *as written* clearly allows it...
>>Actually I can read the specification both ways without much stretch
>>of the imagination...
>Can you explain how you can read it to forbid the {}?

I can read the first yay many paragraphs of the semantics as referring to
the "top level" initializer only, not "inner" subintializers. This is
reinforced by:

>"...the initializer for an object that has aggregate type shall be a
>brace-enclosed list of initializers for the members of the aggregate..."

which cannot be construed as applying to inner subinitializers, because
braces are NOT necessary there.

> "The initializer for a scalar shall be a single expression,
> optionally enclosed in braces. The initial value of the object
> is that of the expression; the same type constraints and
> conversions as for simple assignment apply."

This also clearly is not meant to apply to initialization of inner parts
of an auto struct:
{ struct { int i, j; } s = { somefunc1(), somefunc2() };
...

>If this is meant to apply only to scalars which are not members of
>aggregates, (a) this is not stated, and (b) there is no definition
>of how scalar members *are* initialized. The only rational conclusion,
>based on the text and not on preconceived ideas from elsewhere, is that
>this entire paragraph applies to scalar initializers whether or not they
>are part of aggregate initializers.

As I say, I can conclude otherwise. It's a matter of which portions of
the Semantics are associated just with struct internals, and which are
associated just with the overall (single, top-level) initializer. This
is one of several places in the standard where getting the scope of the
linguistic constraints right is necessary to obtain the right
interpretation. (I don't claim that either of ours is necessarily the
right one, which is why I would like to see an official ruling.)

>>I would urge that this be sent in as an official
>>request for interpretation...
>I'm not sure why; the wording seems clear and specific.

Well, I'm glad it's clear to you, but it sure isn't clear to me.
If anybody else has trouble interpreting just what is and isn't
specified about initializers, as I gather was the case for the
posting that started this thread, I urge them to send X3 a request
for interpretation so we can settle what the rules really are.

Blair P. Houghton

unread,
May 23, 1990, 11:27:18 AM5/23/90
to
In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>In article <1990May22.1...@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>>Can you explain how you can read it to forbid the {}?
>
>I can read the first yay many paragraphs of the semantics as referring to
>the "top level" initializer only, not "inner" subintializers. This is
>reinforced by:
>
>>"...the initializer for an object that has aggregate type shall be a
>>brace-enclosed list of initializers for the members of the aggregate..."
>
>which cannot be construed as applying to inner subinitializers, because
>braces are NOT necessary there.

Unless the subinitializer initializes a member that itself
has an aggregate type. If it doesn't, the braces are optional.

The line you quote is context-independent. It says "an object",
not "the top-level object". I don't see where you get the idea
that those paragraphs are limited in their scope to only the
"top level".

The statement,

"The rest of this section deals with initializers that have
aggregate or union type."
(ANSI X3.159-1989, Sec. 3.5.7, pp. 73, ll. 12)

Doesn't limit the scope of anything above it, but removes
scalars from things below it.

>> "The initializer for a scalar shall be a single expression,
>> optionally enclosed in braces. The initial value of the object
>> is that of the expression; the same type constraints and
>> conversions as for simple assignment apply."
>
>This also clearly is not meant to apply to initialization of inner parts
>of an auto struct:
> { struct { int i, j; } s = { somefunc1(), somefunc2() };

"All expressions in an initializer for an object that has
static storage duration or in an initializer list for an object
that has aggregate or union type shall be constant expressions."
(ANSI X3.159-1989, Sec. 3.5.7, pp. 72, ll. 32-33)

I.e., `somefunc1()' and `somefunc2()' had better be macros.

>>If this is meant to apply only to scalars which are not members of
>>aggregates, (a) this is not stated, and (b) there is no definition
>>of how scalar members *are* initialized. The only rational conclusion,
>>based on the text and not on preconceived ideas from elsewhere, is that
>>this entire paragraph applies to scalar initializers whether or not they
>>are part of aggregate initializers.

Exactly.

>As I say, I can conclude otherwise. It's a matter of which portions of
>the Semantics are associated just with struct internals, and which are
>associated just with the overall (single, top-level) initializer. This
>is one of several places in the standard where getting the scope of the
>linguistic constraints right is necessary to obtain the right
>interpretation. (I don't claim that either of ours is necessarily the
>right one, which is why I would like to see an official ruling.)

Yours is pretty well unfounded, IMO.

It's obvious from the syntax and the given semantics that an
initializer is an initializer, no matter wether it's being
applied to the "top-level object" or the tenth-deep struct-
or-union-member in a volatile-auto context.

>Well, I'm glad it's clear to you, but it sure isn't clear to me.
>If anybody else has trouble interpreting just what is and isn't
>specified about initializers, as I gather was the case for the
>posting that started this thread, I urge them to send X3 a request
>for interpretation so we can settle what the rules really are.

I think the original message was having trouble understanding
that omitted initializers were simply inferred by the compiler,
not whether the braces were optional around scalar-typed objects'
initializers.

The only thing I can conclude is that you don't consider
the members of an aggregate object to be objects themselves.

--Blair
"If it breaks, don't work it."

Ronald Guilmette

unread,
May 23, 1990, 2:17:44 PM5/23/90
to
In article <58...@buengc.BU.EDU> b...@buengc.bu.edu (Blair P. Houghton) writes:
>In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>>In article <1990May22.1...@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>>>Can you explain how you can read it to forbid the {}?
>>
>>I can read the first yay many paragraphs of the semantics as referring to
>>the "top level" initializer only, not "inner" subintializers. This is
>>reinforced by:
>>
>>>"...the initializer for an object that has aggregate type shall be a
>>>brace-enclosed list of initializers for the members of the aggregate..."
>>
>>which cannot be construed as applying to inner subinitializers, because
>>braces are NOT necessary there.
>
>Unless the subinitializer initializes a member that itself
>has an aggregate type. If it doesn't, the braces are optional.
>
>The line you quote is context-independent. It says "an object",
>not "the top-level object". I don't see where you get the idea
>that those paragraphs are limited in their scope to only the
>"top level".

After re-reading section 3.5.7, I am strongly inclidned to agree with Blair
and Henry Spencer (and disagree with Doug Gwyn - sorry Doug).

It seems clear to me that a sub-object of an aggregate is itself "an object".
It also seems clear to me that if such a sub-object is itself a scalar,
then extra (optional) braces around the initializer FOR THAT SUB-OBJECT
are allowed.

>>As I say, I can conclude otherwise. It's a matter of which portions of
>>the Semantics are associated just with struct internals, and which are
>>associated just with the overall (single, top-level) initializer. This
>>is one of several places in the standard where getting the scope of the
>>linguistic constraints right is necessary to obtain the right
>>interpretation. (I don't claim that either of ours is necessarily the
>>right one, which is why I would like to see an official ruling.)
>
>Yours is pretty well unfounded, IMO.
>
>It's obvious from the syntax and the given semantics that an
>initializer is an initializer, no matter wether it's being
>applied to the "top-level object" or the tenth-deep struct-
>or-union-member in a volatile-auto context.
>
>>Well, I'm glad it's clear to you, but it sure isn't clear to me.
>>If anybody else has trouble interpreting just what is and isn't
>>specified about initializers, as I gather was the case for the
>>posting that started this thread, I urge them to send X3 a request
>>for interpretation so we can settle what the rules really are.

I started this thread, but I am now satisfied that an interpretation ruling
is not strictly necessary. Still, it would (obviously) be helpful if the
next revision of the standard contained slightly less cryptic wording.

>I think the original message was having trouble understanding
>that omitted initializers were simply inferred by the compiler,
>not whether the braces were optional around scalar-typed objects'
>initializers.

Actually, when I posted my original message, I was having trouble understanding
the fact that an inner (nested) brace may be treated differently depending
upon its position within the outer initializer list. For example:

struct s {
int a;
int b;
};

struct s array_1[] = { 1, { 2 }, 3 };
struct s array_2[] = { 1, 11, { 2 }, 3 };

In the first instance the inner braces are simply redundant and useless extra
braces around the scalar initializer for array_1[0].b while in the second
case, the inner braces are interpreted as enclosing an entire sub-initializer
list of an entire element of the array `array_2'.

The fact that the meaning of a set of inner braces is effectively position-
dependent is, IMHO, a bad aspect of the standard and should be repealed
at the first opportunity, however I now have absolutely no doubts that
this *is* what the standard calls for (even if I don't like it very much).

// rfg

Henry Spencer

unread,
May 23, 1990, 1:09:43 PM5/23/90
to
In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>I can read the first yay many paragraphs of the semantics as referring to
>the "top level" initializer only, not "inner" subintializers...

That's what I thought... but then there is no way to write such aggregate
initializers, because only the early paragraphs describe how to initialize
a scalar, and the aggregate-initialization section never tells you how
to initialize a scalar member. The early scalar-initializer paragraph
*must* apply to scalar members, or you can't initialize aggregates member
by member at all. And if it applies, surely it *all* applies, including
"optionally enclosed in braces".

You cannot construct a consistent, useful interpretation of the existing
wording if you assume that the early paragraphs apply only to the top level,
because then the inner-level section is hopelessly incomplete.

Agreed that the wording could do with some improvement to clarify the
situation, but as it stands I still see only one possible interpretation.

>This also clearly is not meant to apply to initialization of inner parts
>of an auto struct:
> { struct { int i, j; } s = { somefunc1(), somefunc2() };

This is outlawed anyway, in "Constraints", so it is not relevant.

>As I say, I can conclude otherwise. It's a matter of which portions of
>the Semantics are associated just with struct internals, and which are

>associated just with the overall (single, top-level) initializer...

What portion of the Semantics describes how to initialize a scalar member?

Doug Gwyn

unread,
May 24, 1990, 4:36:35 AM5/24/90
to
In article <58...@buengc.BU.EDU> b...@buengc.bu.edu (Blair P. Houghton) writes:
>>which cannot be construed as applying to inner subinitializers, because
>>braces are NOT necessary there.
>Unless the subinitializer initializes a member that itself
>has an aggregate type. If it doesn't, the braces are optional.

WRONG. Even if it IS an aggregate the braces are optional, as
described farther along in Semantics. Your interpretation would
lead to the conclusion that these two parts of the spec are
contradictory. As I say, I think we need an official ruling here.

Doug Gwyn

unread,
May 24, 1990, 5:06:46 AM5/24/90
to
In article <1990May23.1...@utzoo.uucp> he...@utzoo.uucp (Henry Spencer) writes:
>What portion of the Semantics describes how to initialize a scalar member?

The Semantics section doesn't need to do so, because in the
absence of an explicit statement about it anything that satisfied
the grammar (Syntax) and didn't violate a Constraint would be
acceptable.

Look, I'm not saying that your interpretation is necessarily
wrong, just that so far I haven't been convinced that my
alternative reading can be disproved. Note that if you're
right, several supposedly conforming implementations were
reported as diagnosing strictly conforming code in the
posting that started this thread. That in itself is ground
for concern about how this section should be interpreted.

Blair P. Houghton

unread,
May 24, 1990, 11:30:46 AM5/24/90
to
In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:

After making some allowance for character arrays (i.e., strings,
s.t. the braces may be dropped to allow `char a[] = "foo"') and
wide-string literals, the std says (about aggregates and unions only,
and I've elided the references to unions):

"Otherwise, 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..."
(ANSI X3.159-1989, Sec. 3.5.7, pp. 73, ll. 20-21)

Then it says:

"If the aggregate contains members that are aggregates ...
the rules apply recursively to the subaggregates..."
(Ibid., ll. 24-26, in part)

Which makes me and Henry look tough, but
then it contradicts itself:

"If the initializer of a subaggregate ... begins
with a left brace, the initializers enclosed by that brace and its
matching right brace initialize the members of the subaggregate..."

"Otherwise, only enough initializers from the list are taken to
account for the members of the subaggregate..."

"...any remining initializers are left to initialize the next member
of the aggregate of which the current subaggregate ... is a part."
(Ibid., ll. 26-31, in part)

Which directly contravenes the "apply recursively" rule,
and makes Doug look a little less wrong...

The only rule that applies to aggregates that _doesn't_
apply to subaggregates, it seems, is the one about
requiring braces around its initializer-list.

I'll eat that one fine. All the rest of the rules apply,
however, in the sense that they must be used to interpret
the initializer when the braces exist (in the proper place).

What's needed isn't an interpretation, because I think
the standard is contradictory, here; what's needed is a
rewriting to remove the paradox. Either "the rules apply
recursively", or they don't. Maybe "the previous rules
apply recursively," but that's not what it says.

--Blair
"Wearing out my g-key..."

Henry Spencer

unread,
May 24, 1990, 2:57:13 PM5/24/90
to
In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>>What portion of the Semantics describes how to initialize a scalar member?
>
>The Semantics section doesn't need to do so, because in the
>absence of an explicit statement about it anything that satisfied
>the grammar (Syntax) and didn't violate a Constraint would be
>acceptable.

But but but... what does it *mean*? Doug, if the early paragraph doesn't
tell you how to initialize a scalar member -- optional braces and all --
then *nothing* in the standard describes, for example, how types have to
match and what conversions are applicable for such an initialization.
Is `struct { long a; } foo = { 2 };' strictly conforming? Without that
paragraph, you can't tell, because nothing specifies whether `2' is a
proper initializer for `foo.a'.

>Look, I'm not saying that your interpretation is necessarily
>wrong, just that so far I haven't been convinced that my

>alternative reading can be disproved...

Doug, what *is* your alternative reading? Point to the part of the standard,
with your reading, that tells me whether `2' is a legal initializer for
`foo.a' in the above example! I don't understand how your reading can
possibly work.

Ronald Guilmette

unread,
May 24, 1990, 6:20:09 PM5/24/90
to

Just when I was beginning to think that the rules made sense and that
I actually understood them, Blair shows me that I was wrong on both
counts.

I believe that he has indeed located a contradiction that requires
correction (and not just clarification).

That's fine by me. I never much liked the existing rules (regardless of
interpretation) anyway.

Why should life be so complex? It's tragic, really.

The November 1988 draft Rationale (which is all I have right now) notes
(as an excuse I suppose) the fact that the "base document" (i.e. K&R)
allowed "aggregate initializers with partially elided braces". It notes
however that various implementations often treat such cases differently.

It totally fails to give any rationale for allowing scalar initializers
(either "standalone" ones or ones which are nested within containing
aggregate initializers) to include unnecessary (and possibly confusing)
extra braces.

I believe that both rules are bad, confusing, and (as Blair points out)
that the first of these two rules can lead to a contradiction.

The rules could have been (and perhaps still should be) made far more simple
and intutive by requiring that scalar initializers *never* include braces.

This would in turn force each and every braced list (either nested or
non-nested) to be interpreted as an aggregate (or sub-aggregate) initializer.

I do not believe that such a rule change would break very much (if any) code.
How many people do you know who write stuff like this?

int i = { 7 };
int array[2] = { { 1 }, { 2 } };

If anybody out there *is* doing this, I claim that they should be shot at
sunrise anyway.

I would also suggest that the rules be ammended so that (in fact) "...the
rules apply recursively to the subaggregates...", i.e. so that nested
initializers for subaggregates were required to be braced, however (unlike
my preceeding suggestion) this "correction" might in fact break a good
deal of existing code, for example, the following would become illegal:

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

whereas a legal form would need to look like:

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

I don't know about you, but given that I often find myself maintaining OPCC
(other people's cruddy code) I would much prefer to see the latter form
required. It is a damn lot clearer in my opinion.

P.S. I don't wanna break my own arm while patting myself on the back, but
I just want to say that I'm glad I got this thread started.

Doug Gwyn

unread,
May 24, 1990, 11:25:54 PM5/24/90
to

Well, a rewriting is out of the question. At this stage all that can
be done is to obtain an interpretation ruling from X3J11. I honestly
don't know how they would decide on this one. I do recall vividly
that during public review both Dave Prosser (the Redactor) and I sat
down and independently "played computer" to apply the rules at the
time to parse an example one of the public commenters was having
trouble with. We both thought that there was no ambiguity, but later
found out that we had assumed parsing would proceed from outside in,
whereas the commenter had in effect parsed from inside out. As a
result, some changes were made to the specification to try to make
the parsing less ambiguous. My feeling is that the result is either
contradictory (with respect to format for subaggregate initializers)
or incomplete (in that Henry is right that we should have said more
about inner members if the ENTIRE Semantics was not supposed to apply
to them). Perhaps by going back to, say, the second review round
draft and applying the additional (unstated but intended) outside-in
parse constraint, one could determine what the committee had thought
the rules were supposed to be. We'll probably have to do something
like that when the issue is raised for a formal interpretation ruling.

Doug Gwyn

unread,
May 24, 1990, 11:44:42 PM5/24/90
to
In article <265C5E...@paris.ics.uci.edu> r...@ics.uci.edu (Ronald Guilmette) writes:
>I believe that he [Blair] has indeed located a contradiction that requires

>correction (and not just clarification).

Now, hey, I'm the one who pointed that out. Indeed, it's my main
reason for thinking the alternative interpretation that I've been
proposing needs to be seriously considered as the one intended.

>The November 1988 draft Rationale (which is all I have right now) notes
>(as an excuse I suppose) the fact that the "base document" (i.e. K&R)
>allowed "aggregate initializers with partially elided braces". It notes
>however that various implementations often treat such cases differently.
>It totally fails to give any rationale for allowing scalar initializers
>(either "standalone" ones or ones which are nested within containing
>aggregate initializers) to include unnecessary (and possibly confusing)
>extra braces.

Quite right on all counts. I for one am not sure that it was intended
that the standard allow e.g.
int a[] = { { { { { 1 } } } } } ;

>The rules could have been (and perhaps still should be) made far more simple
>and intutive by requiring that scalar initializers *never* include braces.

Well, we couldn't do that, because the following has long been proper:
int i = { 1 };

That's one of the reasons that I think that different rules were
intended for outermost and inner initializers.

By the way, add the Cray-2 supposedly ANS-conformant "scc" compiler to
the list of those that don't seem to parse { } in an intelligible way.
Maybe the implementor had yet a third reading of the standard on this..

>... for example, the following would become illegal:


> int foo[2][2] = { 1, 2, 3, 4 };
>whereas a legal form would need to look like:
> int foo[2][2] = { { 1, 2 }, { 3, 4 } };

X3J11 considered a motion to require that (within the outer { }) the
initializer list be either fully braced or totally unbraced, but did
not (so far as I can reconstruct events) adopt the proposal.

For programmers, I suggest that subaggregates always be braced and
other members never be individually braced. This practice should
work with any reasonable interpretation of the rules (except on the
Cray-2, apparently).

Blair P. Houghton

unread,
May 25, 1990, 3:01:05 PM5/25/90
to
In article <12...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>In article <265C5E...@paris.ics.uci.edu> r...@ics.uci.edu (Ronald Guilmette) writes:
>>I believe that he [Blair] has indeed located a contradiction that requires
>>correction (and not just clarification).
>
>Now, hey, I'm the one who pointed that out.

Well, hey, you didn't actually point it out, you simply
said it was there, and even then you had it wrapped in a
much larger indication of ambiguity; and, Ron is saying he
agrees with me that an interpretation won't be sufficient.

I don't know the exact definition of "interpretation" as
CBEMA and X3J11 would define it, but if it's what I think
it is (i.e., "putting into other words an existing statement"),
it can't be done given the current statements in the standard.

The "interpretation" will instead have to be a "redefinition".

I'll agree with your "correction is out of the question"
insofar as it's way too soon after the finalization of
the standard to rewrite the thing. Some time should be
taken so that more of these things can be found, or it will
become ridiculously expensive to the entire industry to
even have a standard. Otherwise, we might as well have
spent the time and money on cross-compilers and MyC-to-YourC
translators.

Is there any way to elect and publish amendments to an ANSI
document without having to reapparove and reprint the
entire thing?

>Indeed, it's my main
>reason for thinking the alternative interpretation that I've been
>proposing needs to be seriously considered as the one intended.

I think that if you keep the implications of the examples
(pp. 73ff.) you can get the sense you want. The basic rules
seem to be: "If the left brace aligns with the first named
member of an aggregate, then the brace-enclosed
initializer-list initializes the entirity of that
aggregate; otherwise it initializes the scalar[*]. If the
first member of an aggregate aligns with no left brace in
the initializer-list, then the aggregate is initialized by
taking the initializers in the order in which they appear
in the initializer-list; initializers 'left over' when the
aggregate is fully initialized will be used for the next
object, if the aggregate was part of a larger aggregate.
An aggregate is an aggregate is an aggregate, no matter
whether it contains or is contained by other aggregates."

The alternative, as Ronald says, and I prefer this one,
would be that "initializers for aggregate objects, whether
they are members of other aggregate objects or not, shall
have braces". But, this contravenes just about every example,
and may break existing code, which is why I'd support the
other definition.

[*] The rules already exist for what happens if you try to
initialize a scalar with an initializer-list that has
too many things in it; and it seems to say that the commas
could be taken as comma-operators in an assignment-expression...
here you need an interpretation... would the comma-operator
take precedence over the comma-separator, or vice versa?

--Blair
"Uh-ohhhhhh..."

Doug Gwyn

unread,
May 26, 1990, 3:12:47 AM5/26/90
to
In article <59...@buengc.BU.EDU> b...@buengc.bu.edu (Blair P. Houghton) writes:
>Is there any way to elect and publish amendments to an ANSI
>document without having to reapparove and reprint the entire thing?

Printing doth not an ANS make. There is an entire process that must
be gone through, and we just finished one such. (It took several years.)

There is no way to change the official ANS for C through short-cuts.
However, it is possible for X3J11 to prepare for release "information
bulletins" containing interpretation of the standard; of course the
interpretation should be exactly that and not some wild contradiction
of what the standard actually says. Such interpretations would not
have the legal force of "standard", but we do expect that as civilized
cooperative gentlemen everyone involved would agree to be guided in
THEIR interpretation of the standard by these official bulletins.

diamond@tkovoa

unread,
May 28, 1990, 9:19:38 PM5/28/90
to
In article <13...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:

>... interpretation of the standard; of course the


>interpretation should be exactly that and not some wild contradiction
>of what the standard actually says.

Huh? Some of the interpretations already wildly contradict what the
standard actually says. To be more precise, the standard says some
things that are wildly different from what was intended, and the
interpretations made a lot more sense.

>Such interpretations would not have the legal force of "standard",

We would certainly be better off giving precedence to the interpretations
(at least those already issued) over the wording of the standard itself.

>but we do expect that as civilized cooperative gentlemen

Indeed, in this field, most of the civilized cooperative gentlepersons
are civilized cooperative gentlemen. (And the ratio is similarly
lopsided for those who are uncivilized and/or uncooperative.)
But let's express hopes for ALL civilized cooperative gentlepersons.

>everyone involved would agree to be guided in
>THEIR interpretation of the standard by these official bulletins.

--
Norman Diamond, Nihon DEC dia...@tkou02.enet.dec.com
Proposed group comp.networks.load-reduction: send your "yes" vote to /dev/null.

Doug Gwyn

unread,
May 29, 1990, 9:50:55 AM5/29/90
to
In article <17...@tkou02.enet.dec.com> dia...@tkou02.enet.dec.com (diamond@tkovoa) writes:
>In article <13...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>>... interpretation of the standard; of course the
>>interpretation should be exactly that and not some wild contradiction
>>of what the standard actually says.
>Huh? Some of the interpretations already wildly contradict what the
>standard actually says. To be more precise, the standard says some
>things that are wildly different from what was intended, and the
>interpretations made a lot more sense.

Name one. There has been NO information bulletin so far, and only six
official individual replies to interpretation requests, which I here
summarize (disclaimer: this posting is NOT an official document):

#1. Still being discussed by committee; no resolution yet.

#2. Was a request for changes, not for interpretation.

#3. Was a request for changes, not for interpretation.

#4. Was disambiguated by an editorial change in the final standard.

#5. A strictly conforming program may not contain #pragma, because
as the standard explicitly states, a pragma causes the implementation
to behave in an implementation-defined manner.

#6. strtoul() conversion of a string starting with a minus sign
reports a range error if and only if the rest of the subject sequence
would overflow the range of unsigned longs, otherwise the value is
negated as an unsigned long. This is the only sensible way to
interpret what the standard states for this process.

So which of these "wildly contradict what the standard actually says"?

diamond@tkovoa

unread,
May 29, 1990, 10:31:36 PM5/29/90
to
In article <13...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>In article <17...@tkou02.enet.dec.com> dia...@tkou02.enet.dec.com (diamond@tkovoa) writes:
>>In article <13...@smoke.BRL.MIL> gw...@smoke.BRL.MIL (Doug Gwyn) writes:
>>>... interpretation of the standard; of course the
>>>interpretation should be exactly that and not some wild contradiction
>>>of what the standard actually says.
>>Huh? Some of the interpretations already wildly contradict what the
>>standard actually says. To be more precise, the standard says some
>>things that are wildly different from what was intended, and the
>>interpretations made a lot more sense.
>
>Name one. There has been NO information bulletin so far, and only six
>official individual replies to interpretation requests, which I here
>summarize (disclaimer: this posting is NOT an official document):
>...

I thought there were more than six topics in one of your previous
postings, which was a very informative and helpful (though unofficial)
summary of interpretations. (And I thank you for having posted that.)

Two of the interpretations, which were themselves very informative
and helpful, which wildly contradicted the standard, involved the
persistency of blue paint, and the prohibition of multiple definitions
of an external function when the function never occurs in an expression.

These two do not appear to be among the six in your present posting
(which I replaced by the ellipsis above). Have they been "uninterpreted"?

Doug Gwyn

unread,
May 30, 1990, 7:39:06 AM5/30/90
to
In article <17...@tkou02.enet.dec.com> dia...@tkou02.enet.dec.com (diamond@tkovoa) writes:
>Two of the interpretations, which were themselves very informative
>and helpful, which wildly contradicted the standard, involved the
>persistency of blue paint, and the prohibition of multiple definitions
>of an external function when the function never occurs in an expression.

The other items in my meeting summary posting were not official
interpretation rulings, but a combination of answers to informal
letters and results of discussions about issues raised by members
of X3J11. (For example, I collected a bunch of e-mail discussing
issues about which I wasn't entirely sure of the correct answers,
and took it to the meeting for discussion by one of the subgroups
formed to draw up responses to both formal and informal questions.)

"Blue paint persists" really IS a literal reading of the standard
(3.8.3.4). It was reaffirmed that yes, we really meant that, and
that if it had been intended that the blue paint evaporate at some
point there would have been an additional statement in the standard
to that effect.

3.7 Semantics says:
If an identifier declared with external linkage is used in
an expression (other than as part of the operand of a sizeof
operator), somewhere in the entire program there shall be
exactly one external definition for the identifier;
otherwise, there shall be no more than one.
The last clause was added editorially in the process of preparing
the final document for ANSI, and was ratified unanimously by X3J11
as such. It was deemed a simple oversight, fixed in the final
standard.

0 new messages