By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,086 Members | 1,919 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,086 IT Pros & Developers. It's quick & easy.

Function pointer array as parameter to a function

P: n/a
Hi all,

I have a specific problem passing a function pointer array as a
parameter to a function. I am trying to use a function which takes a
function pointer array as an argument. I am too sure about the syntax
of calling the same.

#include <stdio.h>

void fp1()
{ printf("In fp1\n"); }

void fp2()
{ printf("In fp2\n");}

void fp3()
{ printf("In fp3\n");}

void call_fpn(void (*fp[3])())
{
(*fp[0])();
(*fp[1])();
(*fp[2])();
}

void main()
{
void (*pfn[3])()={NULL};
pfn[0]=&fp1;
pfn[1]=&fp2;
pfn[2]=&fp3;

call_fpn(.....);
}

Can someone please let me know what is the right syntax for calling
the function accepting a function pointer array.

Thanks in advance.
Ar
Jun 27 '08 #1
Share this Question
Share on Google+
26 Replies


P: n/a
ru*********@gmail.com wrote:
Hi all,

I have a specific problem passing a function pointer array as a
parameter to a function. I am trying to use a function which takes a
function pointer array as an argument. I am too sure about the syntax
of calling the same.

#include <stdio.h>

void fp1()
{ printf("In fp1\n"); }

void fp2()
{ printf("In fp2\n");}

void fp3()
{ printf("In fp3\n");}

void call_fpn(void (*fp[3])())
{
(*fp[0])();
(*fp[1])();
(*fp[2])();
}

void main()
{
void (*pfn[3])()={NULL};
pfn[0]=&fp1;
pfn[1]=&fp2;
pfn[2]=&fp3;

call_fpn(.....);
}

Can someone please let me know what is the right syntax for calling
the function accepting a function pointer array.
Isn't

call_fpn(pfn);

enough?
>
Thanks in advance.
Ar

--
Pietro Cerutti
Jun 27 '08 #2

P: n/a
On May 19, 4:18 pm, aruna.mys...@gmail.com wrote:
Hi all,

I have a specific problem passing a function pointer array as a
parameter to a function. I am trying to use a function which takes a
function pointer array as an argument. I am too sure about the syntax
of calling the same.
<snip c code>
Can someone please let me know what is the right syntax for calling
the function accepting a function pointer array.

#include <stdio.h>

#define foo() printf("%s\n", __func__)

void f1() { foo(); }
void f2() { foo(); }
void f3() { foo(); }
void doit(void (**f)()) {
size_t i;

for(i = 0; f[i]; f[i++]())
;
}

int main(void) {

void (*f[4])() = {0};

f[0] = f1;
f[1] = f2;
f[2] = f3;

doit(f);

return 0;
}
Jun 27 '08 #3

P: n/a
ar**********@gmail.com wrote:
I have a specific problem passing a function pointer array as a
parameter to a function. I am trying to use a function which takes a
function pointer array as an argument. I am too sure about the syntax
of calling the same.
You're attempt already looks rather good.
#include <stdio.h>
void fp1()
I think it's better to exactly specify the the types of arguments
(or that no argument is to be expected):

void fp1( void )
{ printf("In fp1\n"); }
void fp2()
{ printf("In fp2\n");}
void fp3()
{ printf("In fp3\n");}
void call_fpn(void (*fp[3])())
{
(*fp[0])();
(*fp[1])();
(*fp[2])();
}
You can simplify that to

void call_fpn( void ( * fp[ 3 ] )( void ) )
{
fp[ 0 ]( );
fp[ 1 ]( );
fp[ 2 ]( );
}

A function pointer followed by parentheses does call the function,
no need to dereference the pointer.

And if you don't want to restrict yourself to an array of
fixed size just use

void call_fpn( void ( ** fp )( void ) )
void main()
main() always returns an int, so make that

int main( void )
{
void (*pfn[3])()={NULL};
You can do the initialization already with the definition:

void ( * pfn[ 3 ] )( void ) = { fp1, fp2, fp3 };
pfn[0]=&fp1;
The name of the function alone is already a pointer to the
function (at least when it's used as a value), so the '&'
isn't necessary.
pfn[1]=&fp2;
pfn[2]=&fp3;
call_fpn(.....);
Just pass 'pfn' as the argument:

call_fpn( pfn );

return 0;
}
Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de
Jun 27 '08 #4

P: n/a
On May 19, 4:50 pm, j...@toerring.de (Jens Thoms Toerring) wrote:
aruna.mys...@gmail.com wrote:
I have a specific problem passing a function pointer array as a
parameter to a function. I am trying to use a function which takes a
function pointer array as an argument. I am too sure about the syntax
of calling the same.

You're attempt already looks rather good.
#include <stdio.h>
void fp1()

I think it's better to exactly specify the the types of arguments
(or that no argument is to be expected):

void fp1( void )
{ printf("In fp1\n"); }
void fp2()
{ printf("In fp2\n");}
void fp3()
{ printf("In fp3\n");}
void call_fpn(void (*fp[3])())
{
(*fp[0])();
(*fp[1])();
(*fp[2])();
}

You can simplify that to

void call_fpn( void ( * fp[ 3 ] )( void ) )
{
fp[ 0 ]( );
fp[ 1 ]( );
fp[ 2 ]( );

}

A function pointer followed by parentheses does call the function,
no need to dereference the pointer.

And if you don't want to restrict yourself to an array of
fixed size just use
He isn't. The [3] really is just informative, but actually a pointer.
<snip>
Jun 27 '08 #5

P: n/a
vi******@gmail.com wrote:
On May 19, 4:50 pm, j...@toerring.de (Jens Thoms Toerring) wrote:

void call_fpn( void ( * fp[ 3 ] )( void ) )

And if you don't want to restrict yourself to an array of
fixed size just use
He isn't. The [3] really is just informative, but actually a pointer.
Of course, you're right.
Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de
Jun 27 '08 #6

P: n/a
On May 19, 2:50*pm, j...@toerring.de (Jens Thoms Toerring) wrote:
aruna.mys...@gmail.com 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

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

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

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

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
Jun 27 '08 #7

P: n/a
Bart <bc@freeuk.comwrote:
On May 19, 2:50*pm, j...@toerring.de (Jens Thoms Toerring) wrote:
aruna.mys...@gmail.com wrote:

You can simplify that to
void call_fpn( void ( * fp[ 3 ] )( void ) )
Consider that parameter type, call it T:
void (*fp[3])void
I guess you meant

void (*fp[3])( void )
How could I modify T to end up with an array [N] of T?
How could I modify T to have a pointer to T?
How could I modify T to have a function returning type T?
I am not sure if I understand your questions correctly, so
what I write in the following might be completely off the
mark...

First thing I would consider when things get too complicated
is using a typedef for the type of function pointer passed
around, e.g.

typedef void ( * func_t )( void );

'func_t' is now a new type that is a pointer to a function
which takes no arguments and returns nothing.

Now you can e.g. write the call_fpn() function as

void call_fpn( func_t fp[ 3 ] )

which already looks a lot more readable.

As someone else already has pointed out the '[3]' bit isn't
really relevant, what the function receives is a pointer to
the first element of an array of function pointers. So you
could also write that as

void call_fpn( func_t fp[ ] )

or

void call_fpn( func_t *fp )

If you now want the call_fpn() function to return a function
pointer of the same type as the ones in the array it got
passed then just change it to e.g.

func_t call_fpn( func_t *fp )
{
fp[ 0 ]( );
fp[ 1 ]( );
return fp[ 2 ];
}

Then you can do in main() e.g.

int main( void )
{
funct_t pfn[ 3 ] = { fp1, fp2, fp3 }
call_fpn( pfn )( );
return 0;
}

This will result in fp1() and fp2() getting called from within
call_fpn() and then the function returned by call_fpn(), fp3,
being called from within main().

If you insist on not using a typedef things will look a lot
uglier. E.g. call_fpn() then would have to be defined instead
of

func_t call_fpn( func_t *fp )

as

void ( * call_fpn( void ( ** fp )( void ) ) )( void )

(I hope I got that right, at least the compiler doesn't com-
plain;-) which I find extremely hard to understand...

Does that about answer what you asked? Otherwise please help
me by trying to describe the problem a bit differently.

Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de
Jun 27 '08 #8

P: n/a
ar**********@gmail.com writes:
I have a specific problem passing a function pointer array as a
parameter to a function. I am trying to use a function which takes a
function pointer array as an argument. I am too sure about the syntax
of calling the same.
[...]

You can't. In C, a function cannot take an array as a parameter.

It can *appear* to do so:

void func(int arr[]);

...

int my_array[42];
func(my_array);

but in fact the parameter "arr" is just a pointer, and the argument
"my_array" is implicitly *converted* to a pointer (to the first
element of the array) when it's evaluated.

See section 6 of the comp.lang.c FAQ, <http://www.c-faq.com/>.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #9

P: n/a
Hi all,

Thank you everyone for your time and responses.

Thanks and Regards,
Ar
Jun 27 '08 #10

P: n/a
On May 19, 4:58*pm, j...@toerring.de (Jens Thoms Toerring) wrote:
Bart <b...@freeuk.comwrote:
On May 19, 2:50*pm, j...@toerring.de (Jens Thoms Toerring) wrote:
aruna.mys...@gmail.com wrote:
You can simplify that to
void call_fpn( void ( * fp[ 3 ] )( void ) )
Consider that parameter type, call it T:
void (*fp[3])void

I guess you meant

void (*fp[3])( void )
Yes.
>
How could I modify T to end up with an array [N] of T?
How could I modify T to have a pointer to T?
How could I modify T to have a function returning type T?

I am not sure if I understand your questions correctly, so
what I write in the following might be completely off the
mark...
...
void ( * call_fpn( void ( ** fp )( void ) ) )( void )

(I hope I got that right, at least the compiler doesn't com-
plain;-) which I find extremely hard to understand...

Does that about answer what you asked? Otherwise please help
me by trying to describe the problem a bit differently.
I find C types incomprehensible other than the simplest.

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. 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.

--
Bartc
Jun 27 '08 #11

P: n/a
Bart <bc@freeuk.comwrote:
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 ___ jt@toerring.de
\__________________________ http://toerring.de
Jun 27 '08 #12

P: n/a
On May 20, 1:07*am, j...@toerring.de (Jens Thoms Toerring) wrote:
Bart <b...@freeuk.comwrote:
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
Jun 27 '08 #13

P: n/a
On May 20, 4:10*am, Bart <b...@freeuk.comwrote:

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
Jun 27 '08 #14

P: n/a
On 20 May, 14:48, Bart <b...@freeuk.comwrote:
On May 20, 4:10*am, Bart <b...@freeuk.comwrote:
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
Jun 27 '08 #15

P: n/a
Bart <bc@freeuk.comwrites:
On May 20, 4:10*am, Bart <b...@freeuk.comwrote:
<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.
Jun 27 '08 #16

P: n/a
On May 20, 3:39*pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
Bart <b...@freeuk.comwrites:
On May 20, 4:10*am, Bart <b...@freeuk.comwrote:
<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
Jun 27 '08 #17

P: n/a
On May 20, 3:31*pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
wrote:
On 20 May, 14:48, Bart <b...@freeuk.comwrote:
On May 20, 4:10*am, Bart <b...@freeuk.comwrote:
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
Jun 27 '08 #18

P: n/a
On May 20, 6:25 pm, Bart <b...@freeuk.comwrote:
On May 20, 3:39 pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
Bart <b...@freeuk.comwrites:
On May 20, 4:10 am, Bart <b...@freeuk.comwrote:
<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.

Jun 27 '08 #19

P: n/a
On May 19, 9:09 am, Bart <b...@freeuk.comwrote:
On May 19, 2:50 pm, j...@toerring.de (Jens Thoms Toerring) wrote:
aruna.mys...@gmail.com 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.
Jun 27 '08 #20

P: n/a
vi******@gmail.com writes:
On May 20, 6:25 pm, Bart <b...@freeuk.comwrote:
>On May 20, 3:39 pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
Bart <b...@freeuk.comwrites:
On May 20, 4:10 am, Bart <b...@freeuk.comwrote:
<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.
Jun 27 '08 #21

P: n/a
On May 20, 11:08 am, John Bode <john_b...@my-deja.comwrote:
On May 19, 9:09 am, Bart <b...@freeuk.comwrote:
[snip]
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
Huh. Not sure if I was being subconsciously smart or just not paying
attention. You asked for a function that returned T, where T is "3-
element array of pointers to functions returning void", but functions
cannot return array types. Functions can return pointers to arrays,
though, hence the above declaration. Sorry if that led to any
confusion.
Jun 27 '08 #22

P: n/a
On May 20, 5:00*pm, vipps...@gmail.com wrote:
On May 20, 6:25 pm, Bart <b...@freeuk.comwrote:
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;
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.
I don't know. If you have cdecl to hand (and it's like mine) try this:

cdecl explain (int (*(*(char))[])[])x

Gives "syntax error"

Now take out the char to leave (), no parameters:

cdecl explain (int (*(*())[])[])x

Gives "cast x into function returning pointer to array of pointer to
array of int"

Why the difference between a function with 0 params and a function
with 1 param? Both are illegal surely?

--
Bartc
Jun 27 '08 #23

P: n/a
In article <e4**********************************@d45g2000hsc. googlegroups.com>
Bart <bc@freeuk.comwrote:
>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;
Probably better to start with the phrase "declare x as" and write:

x

(without the "int" or ";").

Note: I will address parentheses in a moment.
>* To create an array N of that, replace the name x by x[N] or (x[N])
Rather than "replace", we now have "add (append) [N]". To omit
the size of the array, you simply omit the size of the array:

x[N]

or

x[]

(while remembering that without a size, you get an "incomplete
type", or -- if x is eventually going to be a formal parameter,
*and* these are the innermost brackets -- the type gets rewritten
by the compiler, replacing "array of" with "pointer to").
>* 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.
Better yet, simply say "prefix with *". Again, handling parentheses
is something I will get to.
>* To create a function returning that, replace the name x by x() or
(x()). Any parameter types go inside the ().
Instead of "replace", again you should go with "add".

So, we have the rules:

array N of: add "[N]"
pointer to: prefix with "*"
function (args) returning: add (args)

and ultimately you have a C keyword that gives the type-name (or,
if you use those evil :-) typedefs, a typedef-ed name that is not
a keyword but acts as if it were one, except when it does not :-) ).
To put in the C keyword that gives the type-name, just insert it
at the front. (Note: I have deliberately avoided const, volatile,
and restrict qualifiers throughout.)

And now we get to parentheses. Any time you "add or prefix", you
must add parentheses if what you have so far will bind less tightly
than what you are about to add. This is the same rule one uses
for expressions, where, e.g., if you want to multiply by 5, you
will need parentheses if you just added x and y: (x+y)*5 needs the
parentheses. (As we will see in a moment, this is simpler for
declarations than for expressions in general.)

The phrase "bind less tightly" is the key here. Doing it right
every time *is* difficult, at least until you have memorized the
rules and practiced them for quite a while; and you simply have to
memorize and practice: there is no short-cut. Luckily, most people
did a lot of memorizing and practicing when they were children
taking math classes. Thus, you should be familiar with operator
binding, although you might have called it "precedence" (which I
think is not the best word for it). In many languages, including
C, expressions with infix operators have a way of binding some
operators more tightly than others, so that:

result = x1 * x2 + y1 * y2;

"means":

result = (x1 * x2) + (y1 * y2);

(there are some languages, including Lisp and APL, that do away
with "precedence" entirely, but if you are a programmer you should
know enough languages to be familiar with those that have it, and
thus bind some operators more tightly than others).

C is a bit odd in having both a prefix "*" operator (for
pointer-following) and postfix-"[]" and "()" operators (for arrays
and function calls), and even more odd in having the "declaration
mirrors use" rule for declarations. C's set of binding levels (or
"operator precedence") is fairly well-chosen though (albeit with
a few notable exceptions), so that needing extra parentheses for
these is relatively rare. But sometimes they are required.
In particular, array subscripting and function-calling both
bind more tightly than pointer-following, so that -- if v1 and
v2 are variables with appropriate types -- an expression like:

*v1[i]();

binds the same as:

*((v1[i])());

and:

*v2()[i];

binds the same as:

*((v2())[i]);

Again, () and [] (postfix function-call and array-index) bind more
tightly than unary "*" (pointer-following).

Because "declaration mirrors use", these rules apply in declarations
as well. Adding "array N of" or "function (args) returning" to a
declaration means adding [N] or (args) to whatever you have so far.
These will bind more tightly than whatever else you have so far;
so if "whatever else you have so far" has a pointer "*" on the
left, you need to enclose what-you-have-so-far in parentheses.
Since inserting a prefix "*" never binds more tightly (than array-of
or function-returning), you never have to add parentheses at this
point.

Let us run through several examples, then:

- declare x as array 3 of pointer to int.

x -- takes care of "declare x as"
x[3] -- add brackets and size for "array 3 of"
*x[3] -- prefix for "pointer to"
int *x[3] -- insert final type keyword

- declare x as pointer to array 3 of int.

x -- "declare x as"
*x -- "pointer to"
(*x)[3] -- "array 3 of": parentheses before appending
int (*x)[3] -- insert final type keyword.

- declare x as
pointer to
array 4 of
pointer to
function (argsA) returning
pointer to
array 5 of
pointer to
function (argsB) returning
void

x -- declare as x
*x -- pointer to
(*x)[4] -- array 4 of: had to pre-parenthesize
*(*x)[4] -- pointer to
(*(*x)[4])(argsA) -- function (argsA) returning: pre-parenthesize
*(*(*x)[4])(argsA) -- pointer to [etc]
(*(*(*x)[4])(argsA))[5]
*(*(*(*x)[4])(argsA))[5]
(*(*(*(*x)[4])(argsA))[5])(argsB)
void (*(*(*(*x)[4])(argsA))[5])(argsB)

and one last "trick" one:

- declare x as pointer to array 2 of function (void) returning int

x
*x
(*x)[2]
(*x)[2](void) -- ("looks funny"; did you catch the trick yet?)
int (*x)[2](void)

The trick here is that this is an invalid declartion: *x has type
"array 2 of function ..." and "array of function" is a constraint
violation. So although it is possible to write such a declaration,
it need not compile (and must draw a diagnostic).

To turn any of the above into a stand-alone declaration, we need
only add a semicolon. I think it is best to work these without
the semicolons, since we might instead use "= {some initializer};"
for instance.

If you want to handle qualifiers, the rule is to insert them at
the same time as the "*" pointer-to part, just after the "*" (because
const, void, and restrict go with pointers), and then again to
insert const or void (but not restrict) at the "top level" when
you get to the C keyword (or typedef-name-acting-like-a-keyword)
that defines the type. The top-level const-or-void can come either
before or after the C keyword, while "deeper" qualifiers must come
after the "*".
>I'm having trouble however building cast types using this method.
To build a cast, start with "declare x as", build a declaration
for x, and then remove the identifier "x" and enclose the entire
thing in parentheses.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
Jun 27 '08 #24

P: n/a
On May 20, 5:08*pm, John Bode <john_b...@my-deja.comwrote:
On May 19, 9:09 am, Bart <b...@freeuk.comwrote:
On May 19, 2:50 pm, j...@toerring.de (Jens Thoms Toerring) wrote:
aruna.mys...@gmail.com 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
Just what I need for studying, thanks.

The function returning a 3-element array is not an issue, clearly that
would be an illegal construct; but if C did allow it the type would
still be constructed logically.

--
Bartc
Jun 27 '08 #25

P: n/a
In article <19**********************************@f63g2000hsf. googlegroups.com>
Bart <bc@freeuk.comwrote:
>I don't know. If you have cdecl to hand (and it's like mine) try this:

cdecl explain (int (*(*(char))[])[])x

Gives "syntax error"
Whether this is right depends on what cdecl is expected to
do:
>Now take out the char to leave (), no parameters:

cdecl explain (int (*(*())[])[])x

Gives "cast x into function returning pointer to array of pointer to
array of int"
This is what it *would* mean, if it were allowed. (You cannot
cast to "function returning".)
>Why the difference between a function with 0 params and a function
with 1 param? Both are illegal surely?
Both casts are invalid, because you cannot convert a value into
a function. (You can convert a value into a pointer-to-function,
but that requires a "*" inside the innermost parentheses.)

There are multiple versions of cdecl, with differing amounts of
"smarts" as to what is valid, and differing amounts of ability to
const, volatile, and restrict qualifiers, and function parameters.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
Jun 27 '08 #26

P: n/a
On May 20, 7:07*pm, Chris Torek <nos...@torek.netwrote:
In article <e42d1d35-3d9e-4d40-a30c-bc62916a1...@d45g2000hsc.googlegroups.com>

Bart *<b...@freeuk.comwrote:
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;

Probably better to start with the phrase "declare x as" and write:

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

Rather than "replace", we now have "add (append) [N]". *To omit
the size of the array, you simply omit the size of the array:

* * x[N]

or

* * x[]
>* 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.

Better yet, simply say "prefix with *". *Again, handling parentheses
is something I will get to.
* To create a function returning that, replace the name x by x() or
(x()). Any parameter types go inside the ().

Instead of "replace", again you should go with "add".

So, we have the rules:

* * array N of: add "[N]"
* * pointer to: prefix with "*"
* * function (args) returning: add (args)
Thanks these look more reliable than mine, which were just based on a
few observations.
And now we get to parentheses. *Any time you "add or prefix", you
I have a feeling I will just put those in anyway, unless clearly not
needed. I doubt it will make much difference to readability -- to me.
Because "declaration mirrors use", these rules apply in declarations
Yet I don't seem to have as much trouble in using these terms in
expressions; odd.
To build a cast, start with "declare x as", build a declaration
for x, and then remove the identifier "x" and enclose the entire
thing in parentheses.
Yes I've got that one sorted now. And will look for a new cdecl.

--
Bartc

Jun 27 '08 #27

This discussion thread is closed

Replies have been disabled for this discussion.