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