Passing a pointer to a function to the function it points to

A

ais523

I've been doing this sort of thing, and I want to know if it's a
sensible way to act (I think this is correct and portable, but want to
make sure):

int f(int a, void(*b)())
{
static int x=0;
if(x) return a;
x=1;
/* do something with a */
((void(*)(int, void(*)()))b)(a,b);
x=0;
return a;
}

Is this one of the few cases where a cast is actually necessary? The
idea is that b should be of the same type as f, so it can be called
with itself as an argument, but there's no way to write that directly
with a finitely-long prototype. One solution might be to do without
prototypes (I'm not sure if that would work), but I don't really want
to do that. So the other solution's to use a pointer of the wrong
type; void* can't be used because it might not be able to represent a
function pointer, so I used void(*)() (should I have used void(*)
(void) instead?). Is this the right, portable way to go about this? (I
don't write code like (void(*)(int, void(*)())) very often.) Likewise,
is my static int the best way to go about preventing an infinite
regress? (The semantics of the situation are that I want the function
to just return a if it's called a second time from within itself.)
 
B

Ben Bacarisse

ais523 said:
I've been doing this sort of thing, and I want to know if it's a
sensible way to act (I think this is correct and portable, but want to
make sure):

int f(int a, void(*b)())
{
static int x=0;
if(x) return a;
x=1;
/* do something with a */
((void(*)(int, void(*)()))b)(a,b);
x=0;
return a;
}

I suspect you have undefined behaviour here. I have not picked though
the standard to be sure but casts like this often work despite a
disclaimer that they are not guaranteed to work.
Is this one of the few cases where a cast is actually necessary? The
idea is that b should be of the same type as f, so it can be called
with itself as an argument, but there's no way to write that directly
with a finitely-long prototype.

No indeed. Though if a typedef name became defined earlier than it
does one could:

typedef int ftype(int, ftype *); /* not legal */

Anyway, to be *sure* you have no UB, I think you need something like
this:

#include <stdio.h>
#include <stdarg.h>

typedef int Function(int, ...);

int f(int a, ...)
{
if (a == 1)
return a;
else {
Function *fp;
va_list ap;
va_start(ap, a);
fp = va_arg(ap, Function *);
va_end(ap);
return a * fp(a - 1, fp);
}
}

int main(void)
{
printf("5! = %d\n", f(5, f));
return 0;
}

Sorry not to have picked over all you questions, but I suspect the
answer to all the cast-based solutions is UB.
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

I've been doing this sort of thing, and I want to know if it's a
sensible way to act (I think this is correct and portable, but want to
make sure):

int f(int a, void(*b)())
{
static int x=0;
if(x) return a;
x=1;
/* do something with a */
((void(*)(int, void(*)()))b)(a,b);
x=0;
return a;
}

Is this one of the few cases where a cast is actually necessary?

No. You can omit the cast entirely:

int f(int a, void(*b)())
{
static int x=0;
if(x) return a;
x=1;
/* do something with a */
b(a,b);
x=0;
return a;
}

b is declared as a pointer to a function having an unspecified number of
parameters, not as having no parameters. There are some subtleties; you
can't do this if the type of a is short instead of int, for example, but
in the example you gave, it's fine this way.
 
M

Martin Ambuhl

ais523 said:
I've been doing this sort of thing, and I want to know if it's a
sensible way to act (I think this is correct and portable, but want to
make sure):

int f(int a, void(*b)())
{
static int x=0;
if(x) return a;
x=1;
/* do something with a */
((void(*)(int, void(*)()))b)(a,b);
x=0;
return a;
}

Is this one of the few cases where a cast is actually necessary?

I can't see why in the world you would think so. The IOCCC line
> ((void(*)(int, void(*)()))b)(a,b);
can be perfectly well written
b(a,b);
 
A

ais523

I can't see why in the world you would think so. The IOCCC line
can be perfectly well written
b(a,b);

The problem here, from my view, is that b happens to point to a
function that was declared with a prototype, yet it's of a datatype
that says that the function is a K&R-style prototypeless one. Can you
call a prototyped function through a prototypeless pointer?
 
C

Chris Dollin

ais523 said:
(The semantics of the situation are that I want the function
to just return a if it's called a second time from within itself.)

Why?

I mean, how did you come to this interesting state? I've never had to
diddle around temporarily suppressing a possible recursion like that;
I wonder if there's some more straightforward solution to whatever
your actual problem is.
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

The problem here, from my view, is that b happens to point to a function
that was declared with a prototype, yet it's of a datatype that says
that the function is a K&R-style prototypeless one. Can you call a
prototyped function through a prototypeless pointer?

So long as it's a function that could be defined without a prototype, it
doesn't matter whether it actually is.

This means

void f1() {}
void f2(void) {}
void f3(c) char c; {}
void f4(char c) {}
void f5(i) int i; {}
void f6(int i) {}
void f7(int i, ...) {}

char c = 'a';
int i = 1;

int main(void) {
void (*fp)();

fp = f1; fp(); // this is fine
fp = f2; fp(); // this is fine
fp = f3; fp(c); // this is fine
fp = f4; fp(c); // this is not fine
fp = f5; fp(i); // this is fine
fp = f6; fp(i); // this is fine
fp = f7; fp(i); // this is not fine
}

f4 and f7 cannot be defined without a function prototype, so they cannot
be called without a function prototype. The rest can be (or are) defined
without one, so they can be called without one.

If you try to compile this program, you will probably notice that your
compiler complains about the lines that are not fine. In this case, so
long as you don't add casts, it's safe to trust the compiler on which
functions are fine and which aren't.
 
A

ais523

Why?

I mean, how did you come to this interesting state? I've never had to
diddle around temporarily suppressing a possible recursion like that;
I wonder if there's some more straightforward solution to whatever
your actual problem is.

I was implementing a spec which specifically had the 'suppress
recursion' as a special case, I think as a method of preventing an
infinite loop if there were errors upstream.
 
C

Chris Dollin

ais523 said:
I was implementing a spec which specifically had the 'suppress
recursion' as a special case, I think as a method of preventing an
infinite loop if there were errors upstream.

Bizarre. Oh, well, if you're stuck with it, you're stuck with it.
 
D

David Thompson

I've been doing this sort of thing, and I want to know if it's a
sensible way to act (I think this is correct and portable, but want to
make sure):

int f(int a, void(*b)())
{
static int x=0;
if(x) return a;
x=1;
/* do something with a */
((void(*)(int, void(*)()))b)(a,b);
x=0;
return a;
}

Is this one of the few cases where a cast is actually necessary? The

As already said, the cast is not needed as long as the actual argument
types, modified by the default argument promotions (which in this case
do nothing), are compatible with the actual* (prototyped or promoted)
parameters and the actual* parameters do not end with ellipsis.
(* where 'actual' parameters here means the ones in the definition of
the function, not the common-but-not-C terminology of 'actual' = as
provided by caller versus 'formal' = as received by callee.)
idea is that b should be of the same type as f, so it can be called
with itself as an argument, but there's no way to write that directly
with a finitely-long prototype. One solution might be to do without

You can if you 'box' it in a struct: FAQ 1.22 at the usual places and
http://c-faq.com . But that's ugly in a different way. TANSTAAFL.
prototypes (I'm not sure if that would work), but I don't really want
to do that. So the other solution's to use a pointer of the wrong
type; void* can't be used because it might not be able to represent a
function pointer, so I used void(*)() (should I have used void(*)
(void) instead?). Is this the right, portable way to go about this? (I
don't write code like (void(*)(int, void(*)())) very often.) Likewise,

Any type of function pointer can portably losslessly point to any
function; the only requirement is that _when you use it to call_ it
has (been converted to) type compatible with the definition.
(Identical to is the easiest form of compatibility.)

A nonprototype func-ptr type -- like void (*) (/*empty*/) -- has the
feature, perhaps a minor advantage, that you can convert to and from
it without a cast as long as (only) the return type matches.
(Analagous to the uncast conversions for cv? void * data ptrs.)
is my static int the best way to go about preventing an infinite
regress? (The semantics of the situation are that I want the function
to just return a if it's called a second time from within itself.)

(I'm pretty sure) It's the _only_ way if you don't allow passing
additional data explicitly. <OT> In C++ you can sorta fake this with a
parameter that you don't document for your users and declare as
defaulting to some distinguishable value. </>

But it isn't multithread-safe, if that's an issue. (Unless this will
be used only in contexts or states that are already mutexed.)

I agree with CD it's an odd and rather unfortunate requirement.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top