Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Function pointer array as parameter to a function

Reply
Thread Tools

Function pointer array as parameter to a function

 
 
Jens Thoms Toerring
Guest
Posts: n/a
 
      05-20-2008
Bart <(E-Mail Removed)> wrote:
> I find C types incomprehensible other than the simplest.


Me too It's actually a lot simpler to me assembling
them then parsing them.

> So I was after a way of simply building up a complex type step by
> step, working from an left-to-right description in English.


At least in the more complicated cases it isn't left-to-right
but more like zig-zack... KR2 has some subchapter on the topic
(5.12) but that doesn't make it any simpler.

> And starting from a non-trivial type so that I can see how you place any
> new stuff in relation to *, [] and ().


> Typedefs are also a useful build tool but I think I need to be able
> build types out of primary elements first. This is for both straight
> coding, and machine-generated code when readability isn't so
> important.


There's a definitely a logic behind it since e.g. the cdecl program
can deal with such things (and the compiler, of course, also does.
If you want to machine-generate code looking at the sources of that
program may give you some ideas (I didn't, so I can't say how well-
written it is).

But when I have to construct something "by hand" I would start
with a typedef and "expand" the typedef. E.g. if you have a
typedef like

typedef void ( * func_t )( void );

and you want to rewrite

func_t call_fpn( func_t *fp )

in basic types I would replace the 'func_t' parts in the following
way

a) take everything from the typedef before the string 'func_t'
(except the 'typedef' keyword, of course) and replace the
occurence of 'func_t' by it.
b) take everything following 'func_t' in the typedef (except the
semicolon) and put it behind the stuff 'func_t' was applied to
(i.e. everything until the next unbalanced closing paranthesis
or the end of the declaration/function signature, whatever comes
first).

So replacing the first 'func_t' that way in

func_t call_fpn( func_t * fp )

using

typedef void ( * func_t )( void );
^^^^^^^^ ^^^^^^^^^
before after

leads to

void ( * call_fpn( func_t * fp ) )( void )
^^^^^^^^ ^^^^^^^^^
before after

That gets rid of the first instance of 'func_t'. The second one
can be replaced the same way:

void ( * call_fpn( void ( * * fp )( void ) ) )( void )
^^^^^^^^ ^^^^^^^^^
before after

I don't know if that helps at all. But perhaps by approaching
the problem from the point of view that typedefs can be "ex-
panded" by textual replacement on the one hand and that you
can simplify complicated declarations with typedefs on the
other, leading to relatively easy to read declarations, gives
you some ideas of how to approach things in your program...

Regards, Jens
--
\ Jens Thoms Toerring ___ http://www.velocityreviews.com/forums/(E-Mail Removed)
\__________________________ http://toerring.de
 
Reply With Quote
 
 
 
 
Bart
Guest
Posts: n/a
 
      05-20-2008
On May 20, 1:07*am, (E-Mail Removed) (Jens Thoms Toerring) wrote:
> Bart <(E-Mail Removed)> wrote:
> > I find C types incomprehensible other than the simplest.

>
> Me too It's actually a lot simpler to me assembling
> them then parsing them.


OK, I've come up with a technique which I think is along the lines you
suggested with typedefs, but was actually derived by trying lots of
things with cdecl!

This works for types that involve a name of some sort (like
declarations, but not casts, although I'd imagine they'd be similar).

* Start with any declaration that has a name, such as int x;

* To create an array N of that, replace the name x by (x[N])

* To create a pointer to that, replace the name by (*x)

* To create a function returning that, replace the name by (x()). (If
it takes parameters, put those inside the ().)

With the capability of stacking these to any extent. However there are
likely superfluous parentheses in there rendering the result, for
complex cases, even more unreadable.

To try this on the OP's problem, he first wanted an Array 3 of Pointer
to Function taking () and returning Void. Hmmm, I think you have to go
right to left with this:

void x

Now add a function returning that:

void (x()) /* already it's clear the outer () not needed) */

Now a pointer to that, following my rules:

void ((*x)())

Finally, an array[3] of that:

void ((*(x[3]))())

And his call_fpn() function I think wanted a pointer to that lot,
namely:

void ((*((*x)[3]))()) /* the 3 not useful here */

--
Bartc
 
Reply With Quote
 
 
 
 
Bart
Guest
Posts: n/a
 
      05-20-2008
On May 20, 4:10*am, Bart <(E-Mail Removed)> wrote:

I've streamlined the processs to construct arbitrary C type
declarations from English, to avoid extra parentheses:

* Start with any declaration that has a name, such as int x;

* To create an array N of that, replace the name x by x[N] or (x[N])

* To create a pointer to that, replace the name x by (*x), although
when x already has * on it's left, the parentheses are not needed.

* To create a function returning that, replace the name x by x() or
(x()). Any parameter types go inside the ().

(Using the same logic in reverse, it's even possible for a human to
actually figure out what a complex declaration does! But really it
shouldn't be necessary to go to all this trouble..)

I'm having trouble however building cast types using this method.

I've tried doing the above using a dummy name, which is then removed
and the whole thing enclosed in parentheses. And I've tried keeping
the original extra parentheses around each extra addition.

But cdecl is temperamental on these and compilers don't generally tell
you the exact meaning of the type; only lccwin spells it out in
English but it doesn't always correspond to what I think.

So what is the normal technique for a type specification to be
converted from declarative form to a cast?

--
Bartc
 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      05-20-2008
On 20 May, 14:48, Bart <(E-Mail Removed)> wrote:
> On May 20, 4:10*am, Bart <(E-Mail Removed)> wrote:


> I've streamlined the processs to construct arbitrary C type
> declarations from English, to avoid extra parentheses:
>
> * Start with any declaration that has a name, such as int x;


I'm not sure how this helps. Why not start with a bare
identifier? How does your method help with ptr-to-funcs?


> * To create an array N of that, replace the name x by x[N] or (x[N])
>
> * To create a pointer to that, replace the name x by (*x), although
> when x already has * on it's left, the parentheses are not needed.


int x -> int (*x)

this looks wrong. The easiest way is build them up in stages
using typedefs.

With function ptrs I just remember that

int *f ()
is a function returning int*

and
int (*f)()
is a pointer to a function returning int

I don't do clever things with arrays.


> * To create a function returning that, replace the name x by x() or
> (x()). Any parameter types go inside the ().
>
> (Using the same logic in reverse, it's even possible for a human to
> actually figure out what a complex declaration does! But really it
> shouldn't be necessary to go to all this trouble..)


well it becomes necessary if someone insists on using the raw
declaration syntax. Can you decode this one?

void (*signal(int sig, void (*func)(int)))(int);

(assuming I copied it correctly!)


> I'm having trouble however building cast types using this method.


cast types? I think the answer is typedefs again.

/* simple case */
j = (int*)n;

/* ptr-to function taking in tand returning void */
typedef void (*FP)(int);

/* takes an FP and returns an FP */
FP func_s (FP);

so if a cast is needed
func_s ((FP)something_else);


> I've tried doing the above using a dummy name, which is then removed
> and the whole thing enclosed in parentheses. And I've tried keeping
> the original extra parentheses around each extra addition.
>
> But cdecl is temperamental on these and compilers don't generally tell
> you the exact meaning of the type; only lccwin spells it out in
> English but it doesn't always correspond to what I think.
>
> So what is the normal technique for a type specification to be
> converted from declarative form to a cast?


use a typedef

--
Nick Keighley


 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      05-20-2008
Bart <(E-Mail Removed)> writes:

> On May 20, 4:10*am, Bart <(E-Mail Removed)> wrote:

<snip>
> I'm having trouble however building cast types using this method.
>
> I've tried doing the above using a dummy name, which is then removed
> and the whole thing enclosed in parentheses. And I've tried keeping
> the original extra parentheses around each extra addition.
>
> But cdecl is temperamental on these and compilers don't generally tell
> you the exact meaning of the type; only lccwin spells it out in
> English but it doesn't always correspond to what I think.
>
> So what is the normal technique for a type specification to be
> converted from declarative form to a cast?


The normal rule is just to write a declaration, remove the name and
the ; and enclose in ()s. Do you have an example where this is wrong?

--
Ben.
 
Reply With Quote
 
Bart
Guest
Posts: n/a
 
      05-20-2008
On May 20, 3:39*pm, Ben Bacarisse <(E-Mail Removed)> wrote:
> Bart <(E-Mail Removed)> writes:
> > On May 20, 4:10*am, Bart <(E-Mail Removed)> wrote:

> <snip>
> > I'm having trouble however building cast types using this method.

>
> > I've tried doing the above using a dummy name, which is then removed
> > and the whole thing enclosed in parentheses. And I've tried keeping
> > the original extra parentheses around each extra addition.

>
> > But cdecl is temperamental on these and compilers don't generally tell
> > you the exact meaning of the type; only lccwin spells it out in
> > English but it doesn't always correspond to what I think.

>
> > So what is the normal technique for a type specification to be
> > converted from declarative form to a cast?

>
> The normal rule is just to write a declaration, remove the name and
> the ; and enclose in ()s. *Do you have an example where this is wrong?


Now that I try to find an example, it's not so easy!

Probably there was no actual error, apart from actual errors of syntax
and odd things like this:

int ((*((*(x(char)))[]))[]);
int y;

x = (int ((*((*((char)))[]))[]))y;

This a type error (the type returns a function). But decl was quite
happy with the cast when written without the 'char':

(int ((*((*(()))[]))[]))y

But gave a syntax error on: (int ((*((*((char)))[]))[]))y

So just funny things with cdecl.

--
Bartc
 
Reply With Quote
 
Bart
Guest
Posts: n/a
 
      05-20-2008
On May 20, 3:31*pm, Nick Keighley <(E-Mail Removed)>
wrote:
> On 20 May, 14:48, Bart <(E-Mail Removed)> wrote:
>
> > On May 20, 4:10*am, Bart <(E-Mail Removed)> wrote:
> > I've streamlined the processs to construct arbitrary C type
> > declarations from English, to avoid extra parentheses:

>
> > * Start with any declaration that has a name, such as int x;

>
> I'm not sure how this helps. Why not start with a bare
> identifier?


Getting started is actually not so easy! Anyway even I can cope with
int x, y[], *z;

> How does your method help with ptr-to-funcs?


If int fn(char) is a function decl then int (*fn)(char) is a pointer
to it, according to cdecl and using my (old)rule#2.

>
> > * To create an array N of that, replace the name x by x[N] or (x[N])

>
> > * To create a pointer to that, replace the name x by (*x), although
> > when x already has * on it's left, the parentheses are not needed.

>
> int x *-> *int (*x)
>
> this looks wrong. The easiest way is build them up in stages
> using typedefs.


I think my methods are wrong. I tested only on terms of types that
were already well-specified with parentheses.

OK, so I'll go back to my original steps and forget about avoiding
parentheses. If the result obviously doesn't need then, as in your
example, then they can be left out.

>
> With function ptrs I just remember that
>
> int *f ()
> is a function returning int*
>
> and
> int (*f)()
> is a pointer to a function returning int
>
> I don't do clever things with arrays.
>
> > * To create a function returning that, replace the name x by x() or
> > (x()). Any parameter types go inside the ().

>
> > (Using the same logic in reverse, it's even possible for a human to
> > actually figure out what a complex declaration does! But really it
> > shouldn't be necessary to go to all this trouble..)


I meant if the C type system had been done properly!

> well it becomes necessary if someone insists on using the raw
> declaration syntax. Can you decode this one?
>
> void (*signal(int sig, void (*func)(int)))(int);


No, only if written according to my rules. But I'll have a go. It
looks like:

void (*s()) (int)

Which I would have to have to write as: void (*(s()))(int). By
striking and eliminating from the inside out, I did struggle to the
correct result. The params of s or signal are easy: each one is an
independent type and is decoded by itself.


>
> > I'm having trouble however building cast types using this method.

>
> cast types? I think the answer is typedefs again.
>
> * */* simple case */
> * *j = (int*)n;
>
> * */* ptr-to function taking in tand returning void */
> * *typedef void (*FP)(int);
>
> * */* takes an FP and returns an FP */
> * *FP func_s (FP);
>
> so if a cast is needed
> * *func_s ((FP)something_else);


void func_s(int) /* step 1, basic type */
void (*func_s)(int) /* step 2, declared ptr-to-fn */
(void (*)(int))x /* step 3, cast */

I just wrote these myself without any help and checked with cdecl!

In practice yes typedefs can be used but I need to understand this
basic stuff first.

--
Bartc
 
Reply With Quote
 
vippstar@gmail.com
Guest
Posts: n/a
 
      05-20-2008
On May 20, 6:25 pm, Bart <(E-Mail Removed)> wrote:
> On May 20, 3:39 pm, Ben Bacarisse <(E-Mail Removed)> wrote:
>
>
>
> > Bart <(E-Mail Removed)> writes:
> > > On May 20, 4:10 am, Bart <(E-Mail Removed)> wrote:

> > <snip>
> > > I'm having trouble however building cast types using this method.

>
> > > I've tried doing the above using a dummy name, which is then removed
> > > and the whole thing enclosed in parentheses. And I've tried keeping
> > > the original extra parentheses around each extra addition.

>
> > > But cdecl is temperamental on these and compilers don't generally tell
> > > you the exact meaning of the type; only lccwin spells it out in
> > > English but it doesn't always correspond to what I think.

>
> > > So what is the normal technique for a type specification to be
> > > converted from declarative form to a cast?

>
> > The normal rule is just to write a declaration, remove the name and
> > the ; and enclose in ()s. Do you have an example where this is wrong?

Functions, you need to add an extra asterisk (*), ie
int foo(int);
int (*)(int)
> Now that I try to find an example, it's not so easy!
>
> Probably there was no actual error, apart from actual errors of syntax
> and odd things like this:
>
> int ((*((*(x(char)))[]))[]);

Why the redundant parenthesis?
That's equivalent to int (*(*x(char))[])[], and what the function
returns is a pointer to an incomplete array of pointers to incomplete
arrays of int.
> int y;
>
> x = (int ((*((*((char)))[]))[]))y;

x is a function, you cannot assign to it.
>
> This a type error (the type returns a function). But decl was quite
> happy with the cast when written without the 'char':
>
> (int ((*((*(()))[]))[]))y
>
> But gave a syntax error on: (int ((*((*((char)))[]))[]))y
>
> So just funny things with cdecl.

It's funny things with your code, nod cdecl.

 
Reply With Quote
 
John Bode
Guest
Posts: n/a
 
      05-20-2008
On May 19, 9:09 am, Bart <(E-Mail Removed)> wrote:
> On May 19, 2:50 pm, (E-Mail Removed) (Jens Thoms Toerring) wrote:
>
> > (E-Mail Removed) wrote:

>
> > You can simplify that to
> > void call_fpn( void ( * fp[ 3 ] )( void ) )

>
> You seem to be quite good at this:
>
> Consider that parameter type, call it T:
>
> void (*fp[3])void
>


void (*fp[3])(void)

> How could I modify T to end up with an array [N] of T?


Well, let's make sure we understand what T is. To parse a hairy
declaration, I start by finding the leftmost identifier, then work my
way out, remembering that [] and () bind before *:

fp -- fp
fp[3] -- is a 3-element array
*fp[3] -- of pointers
(*fp[3])(void) -- to functions
void (*fp[3])(void) -- returning void

So you want an N-element array of 3-element arrays of pointers to
functions returning void. So we build it up as follows:

fp -- fp
fp[N] -- is an N-element array
fp[N][3] -- of 3-element arrays
*fp[N][3] -- of pointers
(*fp[N][3])(void) -- to functions
void (*fp[N][3])(void) -- retuning void

>
> How could I modify T to have a pointer to T?
>


fp -- fp
*fp -- is a pointer
(*fp)[3] -- to a 3-element array
*(*fp)[3] -- of pointers
(*(*fp)[3])(void) -- to functions
void (*(*fp)[3])(void) -- returning void

> How could I modify T to have a function returning type T?
>


fp -- fp
fp() -- is a function
*fp() -- returning a pointer
(*fp())[3] -- to a 3-element array
*(*fp())[3] -- of pointers
(*(*fp())[3])(void) -- to functions
void (*(*fp())[3])(void) -- returning void


> Please add any parentheses that might be needed.
>
> (I need ask a similar question in a different guise recently. But no
> replies, so it was either incredibly difficult, or so trivial that
> nobody could understand why I was even asking. I contrived a solution
> of sorts but it was unsatisfactory.)
>
> -- Thanks,
>
> Bartc


I'm not sure when I hit on this particular system for reading and
building hairy declarators, but I've had pretty good success with it.
You can also try to work your way from the outside in, using
substitution:

void F(void) -- F = (*P)
void (*P)(void) -- P = fp[3]
void (*fp[3])(void)

but I find the first method more straightforward, and more useful for
building complex declarations.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      05-20-2008
(E-Mail Removed) writes:

> On May 20, 6:25 pm, Bart <(E-Mail Removed)> wrote:
>> On May 20, 3:39 pm, Ben Bacarisse <(E-Mail Removed)> wrote:
>>
>>
>>
>> > Bart <(E-Mail Removed)> writes:
>> > > On May 20, 4:10 am, Bart <(E-Mail Removed)> wrote:
>> > <snip>
>> > > I'm having trouble however building cast types using this method.

>>
>> > > I've tried doing the above using a dummy name, which is then removed
>> > > and the whole thing enclosed in parentheses. And I've tried keeping
>> > > the original extra parentheses around each extra addition.

>>
>> > > But cdecl is temperamental on these and compilers don't generally tell
>> > > you the exact meaning of the type; only lccwin spells it out in
>> > > English but it doesn't always correspond to what I think.

>>
>> > > So what is the normal technique for a type specification to be
>> > > converted from declarative form to a cast?

>>
>> > The normal rule is just to write a declaration, remove the name and
>> > the ; and enclose in ()s. Do you have an example where this is wrong?

> Functions, you need to add an extra asterisk (*), ie
> int foo(int);
> int (*)(int)


They are not the same type. The declaration with a name would be

int (*foo)(int);

and the "rule" correctly gives the cast operator: (int (*)(int)).

--
Ben.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pointer to an array vs pointer to pointer subramanian100in@yahoo.com, India C Programming 5 09-23-2011 10:28 AM
Cast a pointer to array to base class pointer to array Hansen C++ 3 04-24-2010 03:30 PM
Pointer to array of array of const pointer RSL C++ 14 02-19-2010 02:06 PM
Array of pointer and pointer of array erfan C Programming 6 01-28-2008 08:55 PM
Array of pointer Vs Pointer to Array sangeetha C Programming 9 10-09-2004 07:01 PM



Advertisments