[comp.lang.c] function declarator strangeness

tuna@athena.mit.edu (Kirk 'UhOh' Johnson) (05/31/90)

the following bits of grammar are culled from appendix A of K&R (1st
ed.):

    function-declarator:                          /* page 204 */
        declarator ( parameter-list_opt )

    declarator:                                   /* page 194 */
        identifier
        ( declarator )
        * declarator
        declarator ( )
        declarator [ constant-expression_opt ]

so a function "foo" returning a pointer to a function returning an int
would be declared as:

    int (*foo())()
    {
      /* body of foo */
    }

imagine that i'd like "foo" to take one argument, arg, an integer.
given the bits of grammar shown above, i would expect use:

    int (*foo())(arg)
        int arg;
    {
      /* body of foo */
    }

unfortunately, both pcc and gcc choke upon such a declaration. but if
i rearrange things as

    int (*foo(arg))()
        int arg;
    {
      /* body of foo */
    }

both compilers generate code which seems to do the right thing,
despite the fact that this declaration of "foo" doesn't seem to match
the grammar shown in my copy of K&R (1st ed.).

anybody have any helpful comments? how should the function-declarator
grammar really read? if the problem is that K&R (1st ed.) is out of
date, is there a better reference that isn't?

although i will try to keep up with comp.lang.c to look for responses
to my questions, i'd appreciate it if responses could also be e-mailed
so i don't inadvertently miss them.

thanks in advance for any help

kirk
--

-------------------------------------------------------------------------------
kirk johnson                                                    `Eat blue dogs
tuna@masala.lcs.mit.edu                                          and dig life.'

drh@romeo.cs.duke.edu (D. Richard Hipp) (05/31/90)

To: tuna@athena.mit.edu
Subject: Re: function declarator strangeness
Newsgroups: comp.lang.c
In-Reply-To: <1990May30.173922.11825@athena.mit.edu>
Organization: Duke University CS Dept.; Durham, NC
Cc: 
Bcc: 

In article <1990May30.173922.11825@athena.mit.edu> you write:
>the following bits of grammar are culled from appendix A of K&R (1st ed.):
>    function-declarator:                          /* page 204 */
>        declarator ( parameter-list_opt )
>    declarator:                                   /* page 194 */
>        identifier
>        ( declarator )
>        * declarator
>        declarator ( )
>so a function "foo" returning a pointer to a function returning an int
>would be declared as:
>    int (*foo())()
>imagine that i'd like "foo" to take one argument, arg, an integer.
>given the bits of grammar shown above, i would expect use:
>    int (*foo())(arg)
>unfortunately, both pcc and gcc choke upon such a declaration. but if
>i rearrange things as
>    int (*foo(arg))()
>both compilers generate code which seems to do the right thing,
>despite the fact that this declaration of "foo" doesn't seem to match
>the grammar shown in my copy of K&R (1st ed.).

This appears to be a mistake in K&R.  My intuition (based on the
inside-out rule) told me that PCC and GCC had it right.  I went home
and checked my (Nov '85 draft of the) ANSI-C standard and it agrees
as well.  The correct declaration is
            int (*foo(x))(){ ... }
The declaration
            int (*foo())(x){ ... }
is wrong.

The inside-out rule is this:  To find the English description of the
type of an object, start with the objects name, and work toward
the outside.  Example: the incorrect declaration reads:
"foo is function returning pointer to function with argument x returning
integer".  Such is not what you want.  Applying the same inside-out
rule to the first declaration yields: "foo is function with argument x
returning pointer to function returning integer."  That sounds better...

Here is the unraveling again, but broken into a table to better show
what is happening:

        ENGLISH                                        C
       ------------------------------------     -------------------
        foo is                                         foo
        function with argument x returning             foo(x)
        pointer to                                    *foo(x)
        function returning                           (*foo(x))()
        integer                                  int (*foo(x))()