[comp.lang.c] Pointers to functions

mills-cl@pike.cis.ohio-state.edu (christopher mills) (03/07/88)

/*   I think D should have Ada-style comments...  */

	Hello there.  I was writing a compiler for a simple C-like language of
my own design for a single-board 6809 computer of mine, and I got around to
the pointer arithmetic part and wondered what C does when you try to do
pointer arithmetic on a pointer to a function.  I figgured it would generate
an error (since functions do not have a "size"), but being curious, I tried it
on a few C compilers I had around.  Suprisingly, many don't flag it as an
error at all and do something implementation-defined and unpredictable (for
example, Lattice C 3.10 on the Amiga treats it as if it were a char *, which
I find odd, because it generates 68000 code which must be even-address
aligned - I would have at least expected it to treat it as a short *).
	K&R doesn't say anything about this (as far as I know).  I think it
shows a breakdown in the typing system - pointers to functions aren't really
pointers, but a distinct type.  Thoughts?  Flames?

	Oh, and as long as were on our D-wishlist, I'd like to be able to
break and continue from more than one loop (yes, I am one of those people who
use continue a lot).  If this has already been mentioned, apologies - I'm
getting on the tail-end of this one, because rn unsubscribed me when the
system crashed and I hadn't noticed until now...

					Chris

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 _____________________           |     Christopher Mills.
(_)________________   \          |     mills-cl@polaris.cis.ohio-state.edu
  ________________|\   \         |     Current Thought: The trouble with good
 (_)______________\_\   \        |        ideas is everyone wants you to do
   ______________________\       |        something with them...
  (_)____________________|       |     DISCLAMER: I really wish I could blame
                                 |          my thoughts on someone else...
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

hankd@pur-ee.UUCP (Hank Dietz) (03/08/88)

In article <7811@tut.cis.ohio-state.edu>, mills-cl@pike.cis.ohio-state.edu (christopher mills) writes:
> the pointer arithmetic part and wondered what C does when you try to do
> pointer arithmetic on a pointer to a function.  I figgured it would generate
> an error (since functions do not have a "size"), but being curious, I tried it
> on a few C compilers I had around.  Suprisingly, many don't flag it as an
> error at all and do something implementation-defined and unpredictable (for
> example, Lattice C 3.10 on the Amiga treats it as if it were a char *, which
> I find odd, because it generates 68000 code which must be even-address
> aligned - I would have at least expected it to treat it as a short *).
> 	K&R doesn't say anything about this (as far as I know).  I think it
> shows a breakdown in the typing system - pointers to functions aren't really
> pointers, but a distinct type.  Thoughts?  Flames?

This reminded me of a long-standing inconsistency in C in treating
labels.  The old pdp11 C compiler used to think labels were actually
constant-valued pointers to instructions, and you could in fact use
them that way.  According to K&R, this treatment was just plain wrong -
labels are a separate type - but I had a few systems programmers
telling me that the idea is useful AND THAT THEY HAD USED IT.

It seems to me that address arithmetic on pointers to functions ought
to be scaled to maintain alignment, as suggested above, and that this
might be part of a "clean" assembly/monitor interface.  However, as I've
pointed out, one could easily extend this concept to make labels be
treated as the type "pointer to in-line code."  I'm not sure I like
this idea, but, as noted above, I know at least a few C programmers
who'd be happy I mentioned it.  Actually, I guess I'm against the idea
because it would really destroy compile-time flow analysis...  but I
felt I should point out the issue anyway.

						-hankd

rcvie@tuvie (ELIN Forsch.z.) (03/10/88)

In article <7811@tut.cis.ohio-state.edu- mills-cl@pike.cis.ohio-state.edu (christopher mills) writes:
-/*   I think D should have Ada-style comments...  */
-
-	Hello there.  I was writing a compiler for a simple C-like language of
-my own design for a single-board 6809 computer of mine, and I got around to
-the pointer arithmetic part and wondered what C does when you try to do
-pointer arithmetic on a pointer to a function.  I figgured it would generate
-an error (since functions do not have a "size"), but being curious, I tried it
-on a few C compilers I had around.  Suprisingly, many don't flag it as an
-error at all and do something implementation-defined and unpredictable (for
-example, Lattice C 3.10 on the Amiga treats it as if it were a char *, which
-I find odd, because it generates 68000 code which must be even-address
-aligned - I would have at least expected it to treat it as a short *).
-	K&R doesn't say anything about this (as far as I know).  I think it
-shows a breakdown in the typing system - pointers to functions aren't really
-pointers, but a distinct type.  Thoughts?  Flames?

Neither. A correction: K&R say (in my German edition) that only a pointer
to an arry element and an integer may be added or subtracted and that no
other (pointer) arithmetic is allowed. The dpANS says that "one operand shall
be a pointer to an object and the other shall have integral type". An object
is defined as "a region of data storage in the execution environment, the
contents of which can represent values". This is a more liberate definition
for pointer arithmetic than K&R have. In any case, pointer arithmetic on
pointers to functions is prohibited.

In article <7689@pur-ee.UUCP- hankd@pur-ee.UUCP (Hank Dietz) writes:
-This reminded me of a long-standing inconsistency in C in treating
-labels.  The old pdp11 C compiler used to think labels were actually
-constant-valued pointers to instructions, and you could in fact use
-them that way.  According to K&R, this treatment was just plain wrong -
-labels are a separate type - but I had a few systems programmers
-telling me that the idea is useful AND THAT THEY HAD USED IT.
-
-It seems to me that address arithmetic on pointers to functions ought
-to be scaled to maintain alignment, as suggested above, and that this
-might be part of a "clean" assembly/monitor interface.  However, as I've
-pointed out, one could easily extend this concept to make labels be
-treated as the type "pointer to in-line code."  I'm not sure I like
-this idea, but, as noted above, I know at least a few C programmers
-who'd be happy I mentioned it.  Actually, I guess I'm against the idea
-because it would really destroy compile-time flow analysis...  but I
-felt I should point out the issue anyway.

The idea to have the same pointer arithmetic on labels as on pointers to
functions seems to be a good one (in my opinion). It could help system
programmers to solve some problems via tricky programming (I know, I know, ...
tricky programming should not be propagated, but some problems can be solved
*only* by tricky programming). Secondly this would allow additional entry
points into functions. It seems to me as if K&R had something like that in
mind when they reserved the keyword entry. Has anybody information why this
feature has never been implemented?

		Dietmar Weickert,
			ALCATEL-ELIN Research Center, Vienna, Austria.

henry@utzoo.uucp (Henry Spencer) (03/12/88)

> The idea to have the same pointer arithmetic on labels as on pointers to
> functions seems to be a good one (in my opinion)...

X3J11 supports this view entirely, since neither is allowed to participate
in arithmetic in any way.  This is a practical necessity; on some machines,
pointers to functions are very strange "magic cookies" whose contents don't
even slightly resemble pointers to data, and pointers to random spots in
the code basically don't exist.

> ... Secondly this would allow additional entry points into functions.

Some machines cannot do this, period.  It's also not at all clear that it
is particularly useful, which is probably why nobody ever did anything
with the "entry" keyword.
-- 
Those who do not understand Unix are |  Henry Spencer @ U of Toronto Zoology
condemned to reinvent it, poorly.    | {allegra,ihnp4,decvax,utai}!utzoo!henry

wj4@prism.gatech.EDU (JOYE,WILLIAM A) (08/31/89)

Ok, C gurus of the world... is the following code portable and why or why
not? This code compiles and runs correct on gcc, Mac AUX cc, Ultrix cc,
and Mac MPW c. 

extern void printf;

main()
{
	void (*f)() = printf;

	f("Hello, world\n");		/* are these two methods equivalent? */
	(*f)("Hello, world again\n" );
}


JOYE,WILLIAM A
Georgia Institute of Technology, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!wj4
Internet: wj4@prism.gatech.edu
-- 
JOYE,WILLIAM A
Georgia Institute of Technology, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!wj4
Internet: wj4@prism.gatech.edu

john@chinet.chi.il.us (John Mundt) (08/31/89)

In article <1679@hydra.gatech.EDU> wj4@prism.gatech.EDU (JOYE,WILLIAM A) writes:
>Ok, C gurus of the world... is the following code portable and why or why
>not? 
>
>	void (*f)() = printf;
>	f("Hello, world\n");		/* are these two methods equivalent? */
>	(*f)("Hello, world again\n" );

They are.

I noticed the same thing on AT&T 3b2/400's and 3b1's.  The assembly code
generated for either form is exactly the same.  The compiler is not the
latest release.  (I'd made a typo once and expected the program to fail.
It didn't.)

In effect, this means that for pointers to functions, the pointer
is not dereferenced, thus in effect f == *f.

K & R are quite definite in stating the correct form is (*f)(), but
apparently even the gods can lie.

If f holds the address of the start of the function, *f really doesn't
have any meaning.  
-- 
---------------------
John Mundt   Teachers' Aide, Inc.  P.O. Box 1666  Highland Park, IL
john@chinet.chi.il.us
(312) 998-5007 (Day voice) || -432-8860 (Answer Mach) && -432-5386 Modem  

flaps@dgp.toronto.edu (Alan J Rosenthal) (09/01/89)

john@chinet.chi.il.us (John Mundt) writes:
>If f holds the address of the start of the function, *f really doesn't
>have any meaning.  

True, but if f is a pointer to the function, which is what happens in C,
then *f is the function itself, just like if ip is a pointer to an int,
*ip is the int pointed to.  Pointers and addresses are different, and C
only has pointers.  (A pointer cannot be implemented by an address; it
requires additional type information (usually implicit).)

ajr

p.s. I know that pf(x) works, and I know why (followup avoidance tactic).

diamond@csl.sony.co.jp (Norman Diamond) (09/01/89)

In article <1679@hydra.gatech.EDU> wj4@prism.gatech.EDU (JOYE,WILLIAM A) writes:

>extern void printf;
>main()
>{
>	void (*f)() = printf;
>	f("Hello, world\n");		/* are these two methods equivalent? */
>	(*f)("Hello, world again\n" );
>}

The two methods are equivalent.  But I have a question:  why does it
work under gcc?

I understand that gcc uses different calling conventions for ordinary
functions and stdargs (varargs) functions.  That is why you cannot
declare a prototype as just "()" without "..." and then define it
with "...".

The definition of f makes (*f) non-stdargs.  But the actual printf
expects stdargs.  So why does it work?!


-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

karl@haddock.ima.isc.com (Karl Heuer) (09/01/89)

In article <1679@hydra.gatech.EDU> wj4@prism.gatech.EDU (JOYE,WILLIAM A) writes:
>is the following code portable and why or why not?

First, I'll answer the question you probably meant to ask: "When `f' has type
`pointer to function', is `f()' a valid way to invoke it, in addition to
`(*f)()'?"  The answer is "Yes, but this feature is new to ANSI C."  As has
already been mentioned, K&R does not guarantee this.  (But the conclusion
"even the gods can lie" is inappropriate.  It's merely the case that some, but
not all, pre-ANSI compilers allowed this feature as an extension.)

Now, in case you're interested, the answer to the question you asked is "No."

>extern void printf;

Even if you add the parens (I presume they were dropped by accident when you
posted -- I find it hard to believe that so many compilers would accept this
as written), the correct declaration is "extern int printf(char *, ...);" (or
just use "#include <stdio.h>", which defines it).  In pre-ANSI C, omit the
arglist.

>	void (*f)() = printf;

Likewise, the correct declaration here is "int (*f)(char *, ...) = printf", or
just "int (*f)() = printf" in pre-ANSI C.  (It is *not* legal to declare a
function void when you don't plan to use its result.  You must declare its
true type, and then (optionally) cast to void.)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

dhesi@sun505.UUCP (Rahul Dhesi) (09/02/89)

     "Is the following code portable and why or why not?"

Alas!  Invariably when a question like this is asked, people tend to
answer as if the question had really been "is the following code
ANSI-conformant.."   Not that this is necessarily being done in the
reference article, but that it happens so commonly in comp.lang.c that
I thought I would point this out before it begins hapening again.
--
Rahul Dhesi <cirrusl!dhesi@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

henry@utzoo.uucp (Henry Spencer) (09/06/89)

In article <835@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
>
>     "Is the following code portable and why or why not?"
>
>Alas!  Invariably when a question like this is asked, people tend to
>answer as if the question had really been "is the following code
>ANSI-conformant.."

While the two questions are not identical, the correlation between the
answers is very high, and is rapidly getting higher yet.
-- 
V7 /bin/mail source: 554 lines.|     Henry Spencer at U of Toronto Zoology
1989 X.400 specs: 2200+ pages. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

ts@cup.portal.com (Tim W Smith) (09/09/89)

> K & R are quite definite in stating the correct form is (*f)(), but
> apparently even the gods can lie.

The Gods got it right.  The C compiler for the PDP-11/45 under V6 required
(*f)().  f() got an error.

I'm not sure, but I think this allowing of f() came in with PCC.  It was
clearly a bug, which the ANSI committee has chosen to make a feature.

While we are on the subject, try this one:

	(***************f)();

This will also invoke the function on most compilers.  Tell me with a
straight face that this is not a bug.  Does ANSI require this to work?

> If f holds the address of the start of the function, *f really doesn't
> have any meaning.  

It certainly does.  *f means the function that starts at f.

> John Mundt   Teachers' Aide, Inc.  P.O. Box 1666  Highland Park, IL
> john@chinet.chi.il.us

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/09/89)

In article <22005@cup.portal.com> ts@cup.portal.com (Tim W Smith) writes:
>	(***************f)();
>This will also invoke the function on most compilers.  Tell me with a
>straight face that this is not a bug.  Does ANSI require this to work?

Yes.  It's a side effect of the fact that a function is actually called
via a pointer to it.  Since people write sin(x) instead of (*sin)(x),
the Standard had to adopt the rule that the name of a function gets
turned into a pointer to the function in such a context.

>> If f holds the address of the start of the function, *f really doesn't
>> have any meaning.  
>It certainly does.  *f means the function that starts at f.

What could you do with it, other than immediately & it again?
It's not an object in data space, so you can't do things like
store it into a variable or inspect its contents.

Functions are rather like arrays, in that they're not first-class
things in C.  The Standard now allows &array to generate a pointer
to array, but couldn't go all the way and allow array variables etc.
Similarly, C already had a certain degree of confusion about functions
themselves vs. pointers to them.  X3J11 came up with rules that
covered the expected behavior (as well as lead to surprising anomalies
such as the one you mentioned).

chris@mimsy.UUCP (Chris Torek) (09/10/89)

[given the declaration `int (*f)();']

In article <22005@cup.portal.com> ts@cup.portal.com (Tim W Smith) writes:
>I'm not sure, but I think this allowing of f() came in with PCC.  It was
>clearly a bug, which the ANSI committee has chosen to make a feature.

It is not so clear, particularly when done in in C++-style:

	object->manipuator_function(object);

Here it is a nice notation and seems deserving of consideration.  If
the notation does not otherwise muck up the abstraction of the language,
i.e., if it is `free', why not allow it?  The question then is whether
it mucks up the abstraction.  Read on:

>While we are on the subject, try this one:
>	(***************f)();
>This will also invoke the function on most compilers.  Tell me with a
>straight face that this is not a bug.

Okay:  This is not a bug.

>Does ANSI require this to work?

Yes.

The whole thing falls rather naturally out of an alternative view of
all C function calls, in which one decides that `functions' do not
really exist.  Rather like arrays, one can *declare* an object as
a function, but in most contexts, mentioning the *name* of the function
gives instead a pointer to that function.

We already knew the latter, from K&R:

	int foo();		/* declare foo as function */
	int (*f)() = foo;	/* name of function => ptr to function */

The `alternative interpretation' above holds that this is actually
true elsewhere as well: that when we write

	int foo();

	foo(3);

what we really wrote was

	int foo();

	foo	/* this is the name of a function, so it becomes a
		   pointer to the function */
	(	/* this means `apply the pointer on the left */
	3	/* argument to the function */
	)	/* end of the argument list */
	;

In this view, when f is an object of type `pointer to function of args
returning T', the result of the indirection `*f' is the `name' of a
function, which is immediately converted back to a pointer.  Hence
`**f' says `Indirect, obtaining the ``name'' of the function, and then
immediately revert to the pointer; then indirect again, and immediately
revert again.'  No matter how many `*' characters you add, the compiler
simply keeps reverting your function to a pointer-to-function.

The real secret is the decision that the `function locator' that goes
before the left parenthesis that introduces the arguments (if any) is
an ordinary rvalue, and that functions in rvalue contexts become pointers
to functions (just like arrays become pointers to their first members).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

flaps@dgp.toronto.edu (Alan J Rosenthal) (09/13/89)

gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
 >>> If f holds the address of the start of the function, *f really doesn't
 >>> have any meaning.  
 >>It certainly does.  *f means the function that starts at f.
 >What could you do with it, other than immediately & it again?

Call it, of course!
(In an ideal language, that is, not C where you call it via the pointer.)

bruey@cpsin3.cps.msu.edu (Donald E Bruey) (02/04/90)

Is it dumb question time already this year?  Well, since someone has
to ask the first one, it may as well be me.     
 
Can some gracious .netlander please mail me some hints ( a program 
is also quite acceptable) on passing around pointers to functions?
Specifically, I've been doing a lot of numerical methods in programs
and having to call four or five functions in each program.  I don't
want to have to copy the code five times, as in




             if (count = /* value */) then do this function
        else if (count = /* another value */) then do _this_ functino
         etc

        I would rather call it like this

        subroutine ( pointer_to_function,initial_value);
        subroutine ( pointer_to_function_II, initial_value);

   and so on.  this would make my life a lot easier, but I found K&R
   a bit difficult to understand on this issue (surprise!!).  Can anyone
   help me?  Thanks in advance.

  If you do send something, mail is much more reliable than reply. 


  bruey@cpsin3.cps.msu.edu  or even bruey@cpsvax.egr.msu.edu

  

aj3u@wilbury.cs.virginia.edu (Asim Jalis) (05/15/91)

What is the difference between these two (pf is a pointer to a
function, and hello is a function):

pf = hello;	

and 

pf = &hello;

The definitions for pf and hello are as follows:

void (*pf)();	// pointer to a function

void hello()
{
  printf("Hello World\n");
}

I used the two different forms of assignments and got the same output.
Is there a difference between them?

Asim.

dave@cs.arizona.edu (Dave Schaumann) (05/15/91)

In article <AJ3U.91May14140642@wilbury.cs.virginia.edu> aj3u@wilbury.cs.virginia.edu (Asim Jalis) writes:
>What is the difference between these two (pf is a pointer to a
>function, and hello is a function):
>
>pf = hello;	
>
>and 
>
>pf = &hello;
>
>The definitions for pf and hello are as follows:
>
>void (*pf)();	// pointer to a function
>
>void hello()
>{
>  printf("Hello World\n");
>}
>
>I used the two different forms of assignments and got the same output.
>Is there a difference between them?

You have found one of the weirdnesses of ANSI-C.  When you have a pointer
to a function, you (normally) invoke the function by saying

	(*funptr)()

However, ANSI, in it's infinite wisdom, decided that you should be able to
say

	funptr()

in the same context, with similar results.

---- Possible rationalization to follow ... press 'n' if you don't care ----

Actually, I believe this is probably due to an influence from C++, where you
have constructs called "classes" (which are similar in some ways to structs).
Suppose you have a class "foo", with an function called "foo_fn".  Now, you
declare v to be a variable of class foo:

  foo v ;

You now can invoke the function foo_fn on v in the following manner:

  v.foo_fn()

(A pointer to v is an implicit variable in the function call)

This functionality can be mimiced in C in the following manner:

typedef struct FOO {
  ...
  void (*foo_fn) ( struct FOO * ) c;
  ...
  } foo ;

foo v ; /* assume that v.foo_fn is initialized appropriately */

Now, according to the traditional interpretation, you must say

  (*v.foo_fn)(&v) ; /* A ptr to v must be explicitly passed */

To invoke foo_fn on v.  The new interpretation allows you to say

  v.foo_fn(&v) ;

Almost like C++ (almost since you still have to explicitly pass a
pointer to the invoking "variable" (known as "self" in C++)).  Thus,
this feature allows you some measureof "poor man's C++" in ANSI C.
Of course, many of the nice features of C++ must be done by hand...

-- 
Dave Schaumann      | There is no cause so right that one cannot find a fool
dave@cs.arizona.edu | following it.	- Niven's Law # 16

steve@taumet.com (Stephen Clamage) (05/15/91)

aj3u@wilbury.cs.virginia.edu (Asim Jalis) writes:

>What is the difference between these two (pf is a pointer to a
>function, and hello is a function):

>pf = hello;	
>and 
>pf = &hello;

There is no difference.  The oddity is this:  A function designator
appearing in an expression context is replaced by the address of the
function, making a pointer-to-function.  Attempts to take the address
of the function designator are ignored. So
	hello
	&hello
	&&&&&&&&&&&&&&&&hello
are all equivalent.

Similarly, when you dereference a pointer-to-function, you get a
function designator, which is replaced by pointer-to-function.
Consequently,
	pf()
	(*pf)()
	(****************pf)()
are all equivalent.

-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

gwyn@smoke.brl.mil (Doug Gwyn) (05/16/91)

In article <1512@caslon.cs.arizona.edu> dave@cs.arizona.edu (Dave Schaumann) writes:
>Actually, I believe this is probably due to an influence from C++, ...

No.  What we did for the C standard was to rationalize existing practice,
which allowed the use of a function identifier where a pointer-to-function
was needed, and also allowed one to call functions using the unadorned
(except for the parenthesized argument list) identifier.  It had nothing
to do with any attempt to emulate C++.

comeau@ditka.Chicago.COM (Greg Comeau) (05/17/91)

In article <AJ3U.91May14140642@wilbury.cs.virginia.edu> aj3u@wilbury.cs.virginia.edu (Asim Jalis) writes:
>pf = hello;	and     pf = &hello;
>The definitions for pf and hello are as follows:
>void (*pf)();	// pointer to a function
>void hello() {   printf("Hello World\n"); }
>I used the two different forms of assignments and got the same output.
>Is there a difference between them?

There is a difference even though they both end up at the same.

In 'pf = hello;', the function name expression is implicitly converted into
a pointer to a function of the appropriate type (a void(*)()) when in this
context.

With 'pf = &hello;', since the operand of & is a function, it is a pointer
to a function of the appropriate type.  It does not become a pointer to a
pointer to a function.

The C++ style is to use the & form.

- Greg
-- 
	 Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418
                          Producers of Comeau C++ 2.1
          Here:attmail.com!csanta!comeau / BIX:comeau / CIS:72331,3421
                     Voice:718-945-0009 / Fax:718-441-2310

tanner@cdis-1.compu.com (Dr. T. Andrews) (05/17/91)

) [ ``new'' function call syntax via pointer derives from c++ usage ]
I don't think your explanation (function-call syntax derives from c++)
is quite sufficient.  I think that ANSI just made things consistant.
Given
	int (*pf)();
	int f();
	int i, j;
	enum { ci=0x45 };
You can reasonably say
	pf = f;			/* pf now points to function f */
because the bare ``f'' has the type ``pointer to function''.
I can also say
	i = ci;			/* i now has value 0x45 */
	i = 0x45;		/* same here.
The types of ``pf'' and ``f'' are compatible.  So are the types
of ``i'' and ``ci'' (because in expressions, enums are ints),
and the types of ``i'' and ``0x45''.

The trick, in both cases, is that I have constants being assigned
to variables.  Both ``ci'' and ``f'' are constant values.  Now, I
can also say:
	i = f();		/* call func at f, stash value in i */
Why should I not declare that ``f'' is really a function pointer,
and that such things are used by following them with parens?  After
all, we've just seen (through assignment to ``pf'') that we can
interpret the value of ``f'' as a function pointer.

If ``f'' is a function pointer, and so is ``pf'', then why should
we not treat them similarly?  In particular, why should we not
also say:
	i = pf();		/* call func at pf, stash value in i */

We do not use different syntax for
	i = 1;
and
	j = i;
do we?

As a sop to history, I note that some compilers accepted this
argument before ANSI; it was ``prior art'' which has simply been
formalized.  Some compilers required no distinction between the
form of call via the pointer ``pf'' and the name ``f''.  Some did
want the syntax ``(*pf)()''.
-- 
uflorida!ki4pv!cdis-1!tanner {uunet dsinc}!cdin-1!cdis-1!tanner

Kai_Henningsen@ms.maus.de (Kai Henningsen) (05/20/91)

D P Gilbert dpg%extro.ucc.su.OZ.AU @ SUB schrieb am Fr 17.05.1991, 02:18

DP>As I reach for the shift button to put yet another set of left and
DP>right parentheses after a niladic function call I have begun to
DP>wonder how to relieve such tedium. Wouldn't it be nice just to
DP>write the function name without those parentheses (e.g. token.get
DP>instead of token.get() ). The syntax of C tells me why but could it
DP>be bent with a #pragma perhaps? Whenever I want the address of a
DP>function I use "&" so I can understand my code 18 months later.
DP>
DP>I know this amounts to heresy ... apologies in advance

Well, *I* call this common sense ... :-)
--
Kai Henningsen  Internet: kh@ms.maus.de
Muenster         UUCP: any_backbone_that_knows_domains!ms.maus.de!kh
Germany         Fido: kh%maus ms, 2:242/2.6 or Kai Henningsen, 2:242/2.244

worley@compass.com (Dale Worley) (05/22/91)

In article <15859@ms.maus.de> Kai_Henningsen@ms.maus.de (Kai Henningsen) writes:
   D P Gilbert dpg%extro.ucc.su.OZ.AU @ SUB schrieb am Fr 17.05.1991, 02:18

   DP>Wouldn't it be nice just to
   DP>write the function name without those parentheses (e.g. token.get
   DP>instead of token.get() ). The syntax of C tells me why but could it
   DP>be bent with a #pragma perhaps? 

Well, consider that I have:

	int (*(f(void)))(void);

That is, f is a function that returns a pointer to a function that
returns an integer.  Suppose that f has side-effects, and furthermore
that the functions it returns pointers to have side-effects.

There are now three situations I want to specify:

Referring to f, but not calling it.
Calling f, but not calling the function it returns a pointer to.
Calling f, and then calling the function it returns a pointer to.

In C these are specified as "f", "f()", and "f()()", respectively.
If it weren't for those empty parens, it would be very difficult to
specify these unambiguously.  (Languages that don't use empty parens
to indicate niladic function calls (e.g., Algol 68) have strange rules
to specify where the niladic function calls are implied.  To handle
the above cases, explicit casts would be used.)

Similar problems happen with other uses of pointers to functions.
E.g., how do I subscript an array of function pointers without
automatically calling the function?

On top of all that, in C it is impossible to tell whether a function
is niladic, unless the user has been nice and used prototypes in all
his declarations.

Dale Worley		Compass, Inc.			worley@compass.com
--
"If you could have any amount of money... How much would you want?"
"All of it."