[net.lang.c] Function pointer syntax peculiarity

arnold@ucsfcgl.UUCP (Ken Arnold%CGL) (11/27/84)

Looking at the code for qsort(), I came across the following
peculiarity in the syntax and semantics of function pointers.  It seems
that "(*cfunc)()" and "cfunc()" are both equivalent uses of a pointer
to a function "cfunc".  qsort takes, as it's fourth parameter, a
pointer to a function.  Below is a piece of sample pseudo code

	extern int	cmp();

	...
	qsort(<base>, <# of elements>, <width of an element>, cmp);
	...

The qsort declaration is

	qsort(base, nel, width, cfunc)
	char	*base;
	int	nel, width;
	int	(*cfunc)(); { ... }

I have used pointers to functions, and the way I use them is

	(*cfunc)(...);	/* call this syntax 1 */

However, qsort() uses it like this:

	cfunc(...);	/* call this syntax 2 */

which seems to work.  I have tested the code on our 4.2bsd C compiler
(a version of PCC) and both usages generate the same code, and neither
gives a warning message.  Now, having "*f" and "f" mean the same thing
doesn't fit into the normal meaning of unary "*", so which is right?

This sends me scurrying to K&R, which uses syntax 1 in all it's
examples.  I have also always used this sytax.  But after thinking
about it (always a dangerous thing to do :->), it seems to me that
syntax 2 is more consistent with the semantics of the thing.

Consider how you declare that cfunc() is a function, and how you get
the pointer out of that declaration.  The following is typical
(equivalent code for an array is presented on the side for reasons
which will be clear below):

	int	cfunc();		int	integers[12];

		...				...
		some_func(cfunc);		another_func(integers)
		...				...

	some_func(function)		another_func(array)
	int	(*function)();		int	*array;
	{				{
		...				...
		(*function)(10);		i = array[10];
		...				...
	}				}

The name of the function "cfunc" becomes the address of the function in
the same way that the name of the array "integers" becomes the address
of the array.  So why, when you use it, do you have to specify taking
the contents of the variable "function", but not have to do the same
with "array"?

The parallel of these two uses of pointers seems strong.  To get the
address, you use the name.  In the case of the array, the "[10]"
indicates an indirection off of the primary expression, either in the
case of "array[10]" or "integers[10]".  But in the case of arrays, for
some reason, if the primary expression is a function name, the "(10)"
indicates "indirection" from the address, but if the primary expression
is a variable name it does not.

I'm curious what other people think about this.  The current situation
in which BOTH syntax 1 and 2 are allowed concurrently is certainly
confusing and nonsensical.  I would tend to support a change to syntax
2, with syntax 1 usage generating a warning, as the "=+" operators have
done.

It is possible this has been dealt with in the proposed C standard,
which I have yet to see more than a summary of.  If it is, what is the
solution?  While we're at it, where can people get a copy of The Real
Thing?

		Ken Arnold

keesan@bbncca.ARPA (Morris Keesan) (11/29/84)

------------------------------
>From: arnold@ucsfcgl.UUCP (Ken Arnold%CGL)
>Looking at the code for qsort(), I came across the following
>peculiarity in the syntax and semantics of function pointers.  It seems
>that "(*cfunc)()" and "cfunc()" are both equivalent uses of a pointer
>to a function "cfunc".
>
>which seems to work.  I have tested the code on our 4.2bsd C compiler
>(a version of PCC) and both usages generate the same code, and neither
>gives a warning message.
>
>I'm curious what other people think about this.  The current situation
>in which BOTH syntax 1 and 2 are allowed concurrently is certainly
>confusing and nonsensical.  I would tend to support a change to syntax
>2, with syntax 1 usage generating a warning, as the "=+" operators have
>done.
>
>It is possible this has been dealt with in the proposed C standard,
>which I have yet to see more than a summary of.  If it is, what is the
>solution?

    The V7 qsort() uses its function pointer correctly, i.e. (*qscmp)(args),
where qscmp is declared as pointer to function.
    The V7 C compiler (cc) does NOT allow the elided form [ qscmp(args) ], and
produces the error message "Call of non-function".  This is correct behavior
according to the C Reference Manual -- Section 7.1, fourth paragraph of page
186 of K&R: "A function call is a primary expression followed by parentheses
containing . . . the actual arguments . . .  The primary expression must be
of type 'function returning ...' . . ."
    The ability to use functions and function pointers interchangeably looks
like it's probably a Berkloid modification.  It makes a certain amount of
sense.  Section 14.2 of the Manual (p. 209, K&R) says, "If the name of a
function appears in an expression not in the function-name position of a call,
a pointer to the function is generated," and the exhibited behavior in 4.2 is
simply a generalization of this to treat the function name as a pointer in
all cases, and allow function calls to look the same with or without pointers.
However, it is in violation of the language as defined by Kernighan and Ritchie,
and this is supported by the behavior of the V7 "cc", which was written by
Dennis Ritchie.
    The October 17, 1984 Draft of the ANSI standard explicitly allows
(Section 4.1.2) a function call to have either a function or pointer to
function preceding the parentheses.  This seems like a reasonable way to remain
compatible with the behavior of most or all existing compilers.  I would
object to removing the original form for calls of function pointers (i.e. with
the *), or even giving warnings, as this would break all of the old programs
which did it "right", for no good reason (the =+,etc. operators were removed
because of ambiguities).
-- 
			    Morris M. Keesan
			    {decvax,linus,ihnp4,wivax,wjh12,ima}!bbncca!keesan
			    keesan @ BBN-UNIX.ARPA

chris@umcp-cs.UUCP (Chris Torek) (11/30/84)

I think this has been mentioned before.  PCC accepts almost anything as
a function.  Try

	f(g)
	int (*g)();
	{
		(**********g)(1);
	}

for example.

I personally think it makes perfect sense to say

	f(g)
	int (*g)();
	{
		g(1);
	}

but this breaks the nice consistency between the way a variable is
declared and the way it is used.  (It makes sense since a function
name by itself is a pointer to that function; that is, I write

	main()
	{
		int (*f)();
		int foo();

		f = foo;	/* &foo is wrong */
		foo(6);
		(*f)(6);	/* but f(6) is wrong too */
	}

If & and * are inverses, I should be saying either "f = &foo" or
"f(6)", and I should be able to say "(*(&foo))(6)".)

However, "(*f)(<args>)" is correct, and it's a bug/feature that
PCC accepts other forms.
-- 
(This line accidently left nonblank.)

In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (301) 454-7690
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

guy@rlgvax.UUCP (Guy Harris) (11/30/84)

>     The ability to use functions and function pointers interchangeably looks
> like it's probably a Berkloid modification.

Umm, people, *please* remember that just because 4.2BSD supports something
and PDP-11 V7, or System III, or System V, or whatever UNIX you have doesn't
does *NOT* mean "Berkeley did it".  4.2BSD (and 4.1BSD) basically have the
System III VAX PCC, so if the VAX PCC does something and the Ritchie
compiler doesn't, chances are very good that it's a generic PCC change
(excepting things that are obviously specific to the VAX PCC implementation).
"ftime", and "ioctl(TIOC<whatever>)", and the DBM library, and lots of other
things are V7isms, not Berkelyisms (excepting those "ioctl"s that Berkeley
added - there's no obvious way to tell which are Berkeleyisms and which
aren't except by reading the manual).

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

henry@utzoo.UUCP (Henry Spencer) (12/03/84)

Guy Harris is correct.  The lack of need to * a pointer to function when
using it in a call is a PCCism, dating back at least to V7.  (I tried it
on my V7 some while ago, when I noticed that the then-current ANSI C
draft had legitimized this usage; cc objected but pcc took it.)
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry