[comp.lang.c] typedefs and prototypes

tada@athena.mit.edu (Michael Zehr) (09/21/88)

I'm writing a graphics interface library which ends up passing a lot
of pointers to functions.  I've run into a problem with
typedefs and prototypes:


/* typedef and prototype declaration of a widget */

typedef void (*Keyboard_widget)(int key, void *data);

Keyboard_widget kb_widget1;


/* definition of a widget */

void kb_widget1(int c, void *data)
{...}


I get a "conflicts with previous declaration" at that point.  If I try
to define the widget by the typedef, what syntax do i use???

Keyboard_widget kb_widget1  /* where do the formal parameters go??? */
{...}

Anyone have any suggestions?
(The reason why i want to use the typedef is that i have to pass
objects of type Keyboard_widget into some functions, and store them in
structures.  i can use a "normal" prototype for the function but is it
strictly conforming when i later on pass a pointer to that function to
a procedure that's expecting a Keyboard_widget???)

-michael j zehr

gwyn@smoke.ARPA (Doug Gwyn ) (09/21/88)

In article <7135@bloom-beacon.MIT.EDU> tada@athena.mit.edu (Michael Zehr) writes:
>typedef void (*Keyboard_widget)(int key, void *data);
>void kb_widget1(int c, void *data)
>I get a "conflicts with previous declaration" at that point.  If I try
>to define the widget by the typedef, what syntax do i use???

Use exactly the syntax of the typedef, minus "typedef", with the
type name replaced by the identifier.  I.e.
	void (*kb_widget1)(int key, void *data) { ... }

>Keyboard_widget kb_widget1  /* where do the formal parameters go??? */
>{...}

This one is a mystery to me too.  The compilers I've tried this on
are unhappy no matter how I try to use the typedef in defining the
function.  Fortunately the explicit definition is completely
compatible, but it would be nice if the typedef method worked.

karl@haddock.ima.isc.com (Karl Heuer) (09/21/88)

In article <8543@smoke.ARPA> gwyn@smoke.ARPA (Doug Gwyn) writes:
>	void (*kb_widget1)(int key, void *data) { ... }

That can't be right.  If kb_widget1 is supposed to be a pointer to a function,
then its definition would take an initializer, not a function body.

>In <7135@bloom-beacon.MIT.EDU> tada@athena.mit.edu (Michael Zehr) writes:
>>typedef void (*Keyboard_widget)(int key, void *data);

It looks like what you meant to say was:
	typedef void Keyboard_widget(int key, void *data);
which should clear up the error message.  No, you can't use the typedef when
you actually declare the function, since (as you noted) there's no place to
put the formal parameters.  (There's a note in the dpANS that explicitly
forbids inheriting the parameter list through a typedef.)

Note that the typedef is now "function".  To declare an object of type pointer
to function, you should use "Keyboard_widget *pf;".

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

gwyn@smoke.ARPA (Doug Gwyn ) (09/21/88)

In article <7785@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <8543@smoke.ARPA> gwyn@smoke.ARPA (Doug Gwyn) writes:
>>	void (*kb_widget1)(int key, void *data) { ... }
>That can't be right.  If kb_widget1 is supposed to be a pointer to a function,
>then its definition would take an initializer, not a function body.

Hm, that's probably right.
"Never mind."

>>In <7135@bloom-beacon.MIT.EDU> tada@athena.mit.edu (Michael Zehr) writes:
>>>typedef void (*Keyboard_widget)(int key, void *data);
>It looks like what you meant to say was:
>	typedef void Keyboard_widget(int key, void *data);

That's more what I had in mind anyway.

I still can't get some of the PCC-based compilers around here to let
me use function typedefs in the actual function definition.
(Of course the parameter list is not an issue since old-style C
doesn't have prototypes.)

chris@mimsy.UUCP (Chris Torek) (09/21/88)

>In article <7135@bloom-beacon.MIT.EDU> tada@athena.mit.edu
>(Michael Zehr) asks:
>>typedef void (*Keyboard_widget)(int key, void *data);
>>void kb_widget1(int c, void *data)
>>I get a "conflicts with previous declaration" at that point.  If I try
>>to define the widget by the typedef, what syntax do i use???

In article <8543@smoke.ARPA> gwyn@smoke.ARPA (Doug Gwyn) answers:
>Use exactly the syntax of the typedef, minus "typedef", with the
>type name replaced by the identifier.

Right, but:

>I.e.
>	void (*kb_widget1)(int key, void *data) { ... }
>
>>Keyboard_widget kb_widget1  /* where do the formal parameters go??? */
>>{...}
>
>This one is a mystery to me too.

The formal parameters go nowhere: you have declared a type (with
the typedef) or an object (without the typedef) which translates
to `pointer to function(int, void *) returning void'.  Since it is
a pointer, it cannot be a function.

The syntax for `function returning pointer to function(int, void *)
returning void' is, of course,

	void (*here_is_fn(type1 arg1, etc))(int, void *) { ... }

and the formal parameters go where` type1 arg1, etc' sits.  Using
a typedef for `pointer to function(int, void *) returning void',
it simplifies to:

	/* pointer to function arg int arg pointer to void return void */
	/* ^          ^        ^   ^   ^   ^          ^    ^      ^ */
	typedef (*pfAiApvRv)(int, void *);

	pfAiApvRv here_is_fn(type1, arg1, etc) { ... }

Note that you cannot use a typedef to define a function type: i.e.,
`typedef func_arg_int_ret_int int(int);' is illegal.  The problem is
that, given this definition, there is nowhere to put the parentheses
and the formal, so that transforming

	/* identity fn */
	int identity(int i) { return i; }

to

	func_arg_int_ret_int identity { return i??? }

leaves us nowhere to declare `i'.  (If we needed no arguments, it
might work, but it makes the grammar inordinately difficult.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

ggs@ulysses.homer.nj.att.com (Griff Smith) (09/22/88)

In article <7135@bloom-beacon.MIT.EDU>, tada@athena.mit.edu (Michael Zehr) writes:
> 
> I'm writing a graphics interface library which ends up passing a lot
> of pointers to functions.  I've run into a problem with
> typedefs and prototypes:

> /* typedef and prototype declaration of a widget */
> 
> typedef void (*Keyboard_widget)(int key, void *data);
> 
> Keyboard_widget kb_widget1;
> 
> /* definition of a widget */
> 
> void kb_widget1(int c, void *data)
> {...}

> I get a "conflicts with previous declaration" at that point.  If I try
> to define the widget by the typedef, what syntax do i use???


/* Define the layout of a keyboard_widget function */

typedef void kb_widg_fn(int key, void *data);

/* Define a type that is a pointer to a keyboard_widget function */

typedef kb_widg_fn* Keyboard_widget;

/* I'm going to use kb_widget1, which is a keyboard_widget function */

kb_widg_fn kb_widget1;

/* And here it is */

void kb_widget1(int c, void *data) {}

/* This is accepted by C++, release 2.0; I can't speak for ANSI C */
-- 
Griff Smith	AT&T (Bell Laboratories), Murray Hill
Phone:		1-201-582-7736
UUCP:		{allegra|ihnp4}!ulysses!ggs
Internet:	ggs@ulysses.att.com

gwyn@smoke.ARPA (Doug Gwyn ) (09/22/88)

In article <13664@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>Note that you cannot use a typedef to define a function type...

That's a real pity too.  We have an application where a programmer
has to supply functions that match a predetermined interface (they
are called via pointers in a struct).  It would be wonderful if a
typedef could be used for defining the function as well as
declaring the pointers in the struct.

Yet another thing to fix in the "D" language.

english@panarea.usc.edu (Joe English) (09/23/88)

In article <13664@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>Note that you cannot use a typedef to define a function type: i.e.,
>`typedef func_arg_int_ret_int int(int);' is illegal.  The problem is
>that, given this definition, there is nowhere to put the parentheses
>and the formal, so that transforming
>
>	/* identity fn */
>	int identity(int i) { return i; }
>
>to
>
>	func_arg_int_ret_int identity { return i??? }
>
>leaves us nowhere to declare `i'.  (If we needed no arguments, it
>might work, but it makes the grammar inordinately difficult.)

I found out by accident that such a construct does work in Borland's
Turbo C (tm):  I had a slew of functions that took the same parameters
to go into an array, and I included a prototype in the typedef to enable
type-checking when they were called indirectly.  It turns out that if
the typedef includes parameter names, like

typedef int func_t(int i, int j);

then function definitions will only work like this:

func_t foo {
  return i+j;
}

!!! Of course, func_t foo(int a, int b) is a "function returning a
function," so the omission of the parameters in the definition makes
'sense.'  I just tried this construct on gcc, and it (quite rightly)
doesn't work at all.  Question: is giving parameter names in a
function declaration (void foo(int i,int j);) part of the standard?
The Turbo manual says to do this for clarity, but I will drop this
practice if it is nonportable.

      /|/| Joe English
-----< | | j.e. 
  O   \|\| ARPA: english%lipari@oberon.usc.edu

chris@mimsy.UUCP (Chris Torek) (09/23/88)

In article <12326@oberon.USC.EDU> english@panarea.usc.edu (Joe English) writes:
>I found out by accident that such a construct does work in Borland's
>Turbo C (tm): ...

>typedef int func_t(int i, int j);
>
>func_t foo {
>  return i+j;
>}
>
>!!! Of course, func_t foo(int a, int b) is a "function returning a
>function," so the omission of the parameters in the definition makes
>'sense.'

True.  The dpANS says that the definition above (but, I think, NOT
the typedef declaration; for this I would have to check) is illegal.

>I just tried this construct on gcc, and it (quite rightly)
>doesn't work at all.

Incidentally, this has always bothered me about standard Pascal:

	type msgtype = array [1..80] of char; { or whatnot }
	procedure foo(i, j: integer; var msg: msgtype); forward;

	... many pages of code ...

	procedure foo;
	begin
	    { do stuff with i, j, and msg }
	end;
	...

One has to wonder where `i', `j', and `msg' came from:  Information
that is by rights purely local appears in a nonlocal place.

>Question: is giving parameter names in a
>function declaration (void foo(int i,int j);) part of the standard?

Yes.  The names themselves, however, are to be ignored by the compiler
(Turbo C is obviously not doing this).  (Whether this means that

	void foo(int i, char *i);

is legal I do not know.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

karl@haddock.ima.isc.com (Karl Heuer) (09/24/88)

In article <13664@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>Note that you cannot use a typedef to define a function type: i.e.,
>`typedef func_arg_int_ret_int int(int);' is illegal.

On the contrary, it *is* legal, and is even used as an example in the dpANS.
However, such a defined type can only be used to declare a function, not to
define one.

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

jim.nutt@p11.f15.n114.z1.fidonet.org (jim nutt) (09/24/88)

 > From: english@panarea.usc.edu (Joe English)
 > Newsgroups: comp.lang.c
 > 
 > doesn't work at all.  Question: is giving parameter names in a
 > function declaration (void foo(int i,int j);) part of the standard?
 > The Turbo manual says to do this for clarity, but I will drop this
 > practice if it is nonportable.

yes.

jim nutt
'the computer handyman'



--  
St. Joseph's Hospital/Medical Center - Usenet <=> FidoNet Gateway
Uucp: ...{gatech,ames,rutgers}!ncar!noao!asuvax!stjhmc!15.11!jim.nutt

lmiller@venera.isi.edu (Larry Miller) (09/28/88)

In article <13709@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>In article <12326@oberon.USC.EDU> english@panarea.usc.edu (Joe English) writes:
>
>(Whether this means that
>
>	void foo(int i, char *i);
>
>is legal I do not know.)
>-- 
>In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
>Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris


Identifiers in prototypes have scope to the end of the declaration.
The above is not legal (though notice the ancient date on my copy of
the draft.  [Ref:  Draft standard, Nov., 1985 (!), Ss C.5.3.3]

	In a declaration that is not a function definition [i.e., a
	function prototype], any identifier declared in the list has
	function prototype scope, which extends to the end of the
	declaration...


Larry Miller				lmiller@venera.isi.edu (no uucp)
USC/ISI					213-822-1511
4676 Admiralty Way
Marina del Rey, CA. 90292