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

Array [*] declarators

3 views
Skip to first unread message

Joseph S. Myers

unread,
Jan 26, 2001, 3:27:41 PM1/26/01
to
C99 introduces a new type of array declarator where * is present
between the brackets (from 6.7.5.2):

[#3] If, in the declaration ``T D1'', D1 has one of the
forms:

D[ type-qualifier-list-opt assignment-expr-opt ]
D[ static type-qualifier-list-opt assignment-expr ]
D[ type-qualifier-list static assignment-expr ]
D[ type-qualifier-list-opt * ]

and the type specified for ident in the declaration ``T D''
is ``derived-declarator-type-list T'', then the type
specified for ident is ``derived-declarator-type-list array
of T''.121) (See 6.7.5.3 for the meaning of the optional
type qualifiers and the keyword static.)

[#4] If the size is not present, the array type is an
incomplete type. If the size is * instead of being an
expression, the array type is a variable length array type
of unspecified size, which can only be used in declarations
with function prototype scope;122) such arrays are
nonetheless complete types. If the size is an integer
constant expression and the element type has a known
constant size, the array type is not a variable length array
type; otherwise, the array type is a variable length array
type.

____________________

121When several ``array of'' specifications are adjacent, a
multidimensional array is declared.

122Thus, * can be used only in function declarations that
are not definitions (see 6.7.5.3).

(a) This introduces complete array types of unknown size. What is the
effect of applying sizeof to such a type? 6.5.3.4 paragraph 1 has a
constraint that sizeof shall not be applied to an incomplete type, but
these types are complete. For example, does the code

void foo(int a, int b[*][*], int c[sizeof(*b)]);

violate any constraints, or have defined behavior, or have undefined
behavior through lack of any definition?

(b) Does the restriction to function prototype scope declarations for
these declarators also apply to the corresponding syntax for abstract
declarators?

(c) For example, is sizeof(int (*)[*]) valid only within a parameter
declaration that is part of a function declaration that is not a
function definition?

--
Joseph S. Myers
js...@cam.ac.uk

Nick Maclaren

unread,
Jan 26, 2001, 4:34:16 PM1/26/01
to
In article <94smjt$gdn$1...@pegasus.csx.cam.ac.uk>,

Joseph S. Myers <js...@cam.ac.uk> wrote:
>
>(a) This introduces complete array types of unknown size. What is the
>effect of applying sizeof to such a type? 6.5.3.4 paragraph 1 has a
>constraint that sizeof shall not be applied to an incomplete type, but
>these types are complete. For example, does the code
>
> void foo(int a, int b[*][*], int c[sizeof(*b)]);
>
>violate any constraints, or have defined behavior, or have undefined
>behavior through lack of any definition?

This came up on the reflector, and many people were very unhappy about
this aspect of the language, but there doesn't appear to be a problem.
It is fully and unambiguously stated, though about half the readers
cannot believe their eyes, and so assume they have misunderstood.

That is a perfectly correct construction, and is equivalent to:

void foo(int a, int b(*)[*], int *c);

It relies on the fact that array parameter adjustment is performed
BEFORE the rest of type analysis. There was a long debate over
whether the following are legal:

void fred (int a[-1]);
and:
void fred (int a[0/0]);

And the consensus was that the first had to be, despite the fact that
nobody was very happy about it, but that the second wasn't. Consensus
is perhaps a strong word, but at least the heated debate wound down
without actually turning into mere abuse ....

Assuming that the consensus is correct, this is an example of when
gcc is not conforming, even with -ansi -pedantic. Nobody could get
terribly excited about requiring implementations to support that sort
of construction, though. The expression "deliberate perversity"
springs to mind.

>(b) Does the restriction to function prototype scope declarations for
>these declarators also apply to the corresponding syntax for abstract
>declarators?

I can't see why not.

>(c) For example, is sizeof(int (*)[*]) valid only within a parameter
>declaration that is part of a function declaration that is not a
>function definition?

As I read the syntax chart, that isn't a declaration and wouldn't
have function prototype scope if it were, so the answer is "no".


Regards,
Nick Maclaren,
University of Cambridge Computing Service,
New Museums Site, Pembroke Street, Cambridge CB2 3QG, England.
Email: nm...@cam.ac.uk
Tel.: +44 1223 334761 Fax: +44 1223 334679

Joseph S. Myers

unread,
Jan 26, 2001, 5:01:52 PM1/26/01
to
In article <94sqgo$k3v$1...@pegasus.csx.cam.ac.uk>,

Nick Maclaren <nm...@cus.cam.ac.uk> wrote:
>It relies on the fact that array parameter adjustment is performed
>BEFORE the rest of type analysis. There was a long debate over
>whether the following are legal:
>
> void fred (int a[-1]);
>and:
> void fred (int a[0/0]);
>
>And the consensus was that the first had to be, despite the fact that
>nobody was very happy about it, but that the second wasn't. Consensus
>is perhaps a strong word, but at least the heated debate wound down
>without actually turning into mere abuse ....

Why should the constraints on array declarators (6.7.5.2 paragraph 1)
not apply to the first of these? The response to DR#047 said that

/* 4 */ int *h(int a2[][]) {return *a2; }

was not strictly conforming (at the time arrays of incomplete type
were undefined behavior; C99 made them constraint violations):

As an aside, array parameters are adjusted to pointer type (subclause
6.7.1, page 82, lines 23-24). However, there is nothing to suggest
that a not-strictly-conforming array type can magically be transformed
into a strictly conforming pointer parameter via this rule.
The types in question can be interpreted two different ways. (Array to
pointer conversion can happen as soon as possible or as late as
possible.) Hence a program that uses such a form has undefined
behavior.

Has C99 changed this so that the example above from DR#047 is now
strictly conforming?

>>(c) For example, is sizeof(int (*)[*]) valid only within a parameter
>>declaration that is part of a function declaration that is not a
>>function definition?
>
>As I read the syntax chart, that isn't a declaration and wouldn't
>have function prototype scope if it were, so the answer is "no".

However, it might appear within a declaration with function prototype
scope, e.g.

void foo(int x[sizeof(int (*)[*])]);

Does this count as being "used in declarations with function prototype
scope"?

Nick Maclaren

unread,
Jan 26, 2001, 5:50:17 PM1/26/01
to
In article <94ss4g$ir4$1...@pegasus.csx.cam.ac.uk>,

Joseph S. Myers <js...@cam.ac.uk> wrote:

No. I don't know what that response is on about. The first half is
correct, and explains why the example is illegal.

The second half flatly contradicts the flames that I have received
from many members of the committee, existing practice and all that.
The reason that the example is invalid is that is gets adjusted to:

int *h(int a2(*)[]) {return *a2; }

which isn't any more legal than the first form. The adjustment does
not recurse.

>>>(c) For example, is sizeof(int (*)[*]) valid only within a parameter
>>>declaration that is part of a function declaration that is not a
>>>function definition?
>>
>>As I read the syntax chart, that isn't a declaration and wouldn't
>>have function prototype scope if it were, so the answer is "no".
>
>However, it might appear within a declaration with function prototype
>scope, e.g.
>
> void foo(int x[sizeof(int (*)[*])]);
>
>Does this count as being "used in declarations with function prototype
>scope"?

As I understand it, no. I read it as implying that the variable length
declaration (a) must be a declaration and not just a type and (b) must
have function prototype scope. I.e. "used in" means "used in that
precise context" and not "used textually within".

Joseph S. Myers

unread,
Jan 30, 2001, 6:13:58 AM1/30/01
to
In article <94suv9$nqa$1...@pegasus.csx.cam.ac.uk>,

Nick Maclaren <nm...@cus.cam.ac.uk> wrote:
>In article <94ss4g$ir4$1...@pegasus.csx.cam.ac.uk>,
>Joseph S. Myers <js...@cam.ac.uk> wrote:

>>Why should the constraints on array declarators (6.7.5.2 paragraph 1)
>>not apply to the first of these? The response to DR#047 said that
>>
>> /* 4 */ int *h(int a2[][]) {return *a2; }
>>
>>was not strictly conforming (at the time arrays of incomplete type
>>were undefined behavior; C99 made them constraint violations):
>>
>> As an aside, array parameters are adjusted to pointer type (subclause
>> 6.7.1, page 82, lines 23-24). However, there is nothing to suggest
>> that a not-strictly-conforming array type can magically be transformed
>> into a strictly conforming pointer parameter via this rule.

>No. I don't know what that response is on about. The first half is


>correct, and explains why the example is illegal.
>
>The second half flatly contradicts the flames that I have received
>from many members of the committee, existing practice and all that.
>The reason that the example is invalid is that is gets adjusted to:
>
> int *h(int a2(*)[]) {return *a2; }
>
>which isn't any more legal than the first form. The adjustment does
>not recurse.

It seems to me that the adjusted form

int *h(int (*a2)[]) {return *a2; }

is legal (a pointer to an incomplete array type being itself a
complete type). But the constraint (that the element type shall not
be an incomplete or function type) is stated as applying to array
declarators rather than to array objects - and I don't see anything
that disapplies 6.7.5.2 paragraph 1 from array declarators where the
array declarator gets adjusted to a pointer - and the constraints on
use of "static" and type qualifiers suggest that such array
declarators are being covered in that paragraph.

What of the following similar examples? In C99, are they legal,
constraint violations, or undefined?

struct S *f(struct S a[]) { return a; }

void g(void (x[])(void));

Nick Maclaren

unread,
Jan 30, 2001, 6:49:49 AM1/30/01
to

In article <9567lm$poq$1...@pegasus.csx.cam.ac.uk>, js...@cam.ac.uk (Joseph S. Myers) writes:
|> >
|> >The second half flatly contradicts the flames that I have received
|> >from many members of the committee, existing practice and all that.
|> >The reason that the example is invalid is that is gets adjusted to:
|> >
|> > int *h(int a2(*)[]) {return *a2; }
|> >
|> >which isn't any more legal than the first form. The adjustment does
|> >not recurse.
|>
|> It seems to me that the adjusted form
|>
|> int *h(int (*a2)[]) {return *a2; }
|>
|> is legal (a pointer to an incomplete array type being itself a
|> complete type). ...

Heck - you're right! This mess is FAR worse than even I have
claimed in the past :-(

I am at a loss to know at which stage in the type management the
array parameter adjustment (a) MAY occur and (b) MUST occur.

The best guess that I can make is that it occurs at the same time
that the identifier is bound to its declarator, and therefore is
part of the textually sequential parsing aspect, rather than the
BNF model parsing aspect. But I can't guarantee that I haven't
missed something else.

Even if I am right, it is not clear whether that is REQUIRED, and
it makes a difference to constructions like:

void fred (int a[], int b[sizeof(a)]);

void fred (int a[-1]);

void fred (int a, int b[a]);
fred(-1,x);

0 new messages