Function pointer to void function and int function

  • Thread starter Giannis Papadopoulos
  • Start date
G

Giannis Papadopoulos

I have the following code

#include <stdio.h>

void a(void) {
printf("a called.\n");
}

int b(void) {
printf("b called.\n");

return 0x1;
}

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

p = a;
p();
p = b;
p();

return 0;
}

However, it does issue a warning that I am trying to assign a function
of wrong type. Is there any portable way to say to the compiler "shut
up, I know what I am doing?"

And what is the most common way of declaring and using function
pointers, the above or this?

p = &a;
(*p)();



--
one's freedom stops where others' begin

Giannis Papadopoulos
http://dop.users.uth.gr/
University of Thessaly
Computer & Communications Engineering dept.
 
E

Eric Sosman

Giannis said:
I have the following code

#include <stdio.h>

void a(void) {
printf("a called.\n");
}

int b(void) {
printf("b called.\n");

return 0x1;
}

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

p = a;
p();
p = b;
p();

return 0;
}

However, it does issue a warning that I am trying to assign a function
of wrong type. Is there any portable way to say to the compiler "shut
up, I know what I am doing?"

Yes, there is:

p = (void(*)(void))b;

However, you'd be telling a lie, because you *don't* know what
you're doing! The subsequent `p();' invokes undefined behavior,
because it uses a pointer of one type to call a function of a
different type. You wouldn't expect

double (*q)(const char*) = (double(*)(const char*))strlen;
double d = q("Hello, world!");

to work, would you? Well, the situation's no different in your
code: the pointer does not match the function, the compiler puts
together the wrong kind of function linkage, and anything can
happen.
And what is the most common way of declaring and using function
pointers, the above or this?

p = &a;
(*p)();

It's a matter of taste, I think. I seldom see `p = &a;',
perhaps for the same reason that `char *s = "Hello, world!";' is
more common than `char *s = &"Hello, world!"[0];'. As for the
call, on some pre-Standard compilers this form was required, and
coders who worked in those days may still use it out of habit.
Some may continue to do so just to make it clear that the call
is using a function pointer and not a literal function name; they
feel the code is more "self-documenting" if written this way.
I prefer to write `p();' instead of the more cluttered `(*p)();',
but the preference isn't a strong one.
 
G

Giannis Papadopoulos

Eric said:
Yes, there is:

p = (void(*)(void))b;

However, you'd be telling a lie, because you *don't* know what
you're doing! The subsequent `p();' invokes undefined behavior,
because it uses a pointer of one type to call a function of a
different type. You wouldn't expect

double (*q)(const char*) = (double(*)(const char*))strlen;
double d = q("Hello, world!");

to work, would you? Well, the situation's no different in your
code: the pointer does not match the function, the compiler puts
together the wrong kind of function linkage, and anything can
happen.

Yes but all I want is to ignore the returning value.
And I need a function pointer to switch between the 2.

Hmm, maybe this would be better?

#include <stdio.h>

void a(void) {
printf("a called.\n");
}

int b(void) {
printf("b called.\n");
return 0x1;
}

static void c(void) {
b();
}

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

p = &a;
p();
p = &c;
p();

return 0;
}

--
one's freedom stops where others' begin

Giannis Papadopoulos
http://dop.users.uth.gr/
University of Thessaly
Computer & Communications Engineering dept.
 
E

Eric Sosman

Giannis said:
Eric said:
[... function pointer type must match type of called function ...]
Yes but all I want is to ignore the returning value.
And I need a function pointer to switch between the 2.

The issue is that the type of the function's value is
part of the "signature," and can influence the way the function
is called and the way its returned value (if any) is retrieved.
For example, some implementations compile

struct foo func(void) {
struct foo f;
...
return f;
}
...
struct foo f2 = func();

as if it had been written

void func(struct foo* _value_ptr) {
struct foo f;
...
*_value_ptr = f;
}
...
struct foo f2;
struct foo _returned_struct;
foo(&_returned_struct);
f2 = _returned_struct;

to avoid the need to find a "secret place" (stack, register,
whatever) that's suitable for holding a possibly large struct.
If you call such a function through a `(void(*)(void))' pointer,
the compiler will not know it's supposed to generate the hidden
`_value_ptr' argument nor the hidden `_returned_struct' object
it should point to. Even if you intend to ignore the returned
value, it's obvious such a call is wrong and possibly fatal.

Now, on many machines it will turn out that the machinery
that calls a function returning `int' and ignores the returned
value is identical to the machinery that calls a `void' function.
This is partly accidental, but also partly intentional. In pre-
Standard C there was no `void', so the way one wrote what we'd
now describe as a `void' function was to write a function that
(formally speaking) was `int'-valued, even though it would not
actually return a value. The people who develop C compilers have
considerable incentive to see to it that as much old code as
possible continues to work, so there's an excellent chance that
you'll get away with your abuse of the language. However, it
is an abuse, and new code should avoid it. Someday, somebody
will find he can generate more efficient code if he does not
cater to practices that are more than fifteen years out of date,
and then where will you be? Don't Do That.
Hmm, maybe this would be better?

#include <stdio.h>

void a(void) {
printf("a called.\n");
}

int b(void) {
printf("b called.\n");
return 0x1;
}

static void c(void) {
b();
}

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

p = &a;
p();
p = &c;
p();

return 0;
}

This is fine. In fact, this is an excellent technique
for using pointers to call functions that may have widely
different argument and result types: You "wrap" each target
function in a "helper" function, and see to it that all the
helpers have the same type.
 
B

Barry Schwarz

Yes but all I want is to ignore the returning value.

But you can't. The compiler knows the code for any function called
via p returns nothing. Therefore, it can make assumptions about what
happens when such a function returns. For example, if int returns are
always done in register x, then register x will be unchanged. If
register x is used by code before and after the function call, then it
may not be necessary to reload its value.

In your case, after p=b this will no longer be true. b() changed the
value of register x but the compiler doesn't know it. It might
attempt to reuse the value of register x but now it will get the
residue from b().
And I need a function pointer to switch between the 2.

There are other techniques that don't lead to undefined behavior, such
as a wrapper function, if-then, changing a() so it always returns 0,
etc.
Hmm, maybe this would be better?

#include <stdio.h>

void a(void) {
printf("a called.\n");
}

int b(void) {
printf("b called.\n");
return 0x1;
}

static void c(void) {
b();
}

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

p = &a;

The & is superfluous.
p();
p = &c;
p();

return 0;
}
In the sense that it does not lead to undefined behavior, yes, it is
better.


<<Remove the del for email>>
 
B

Barry Schwarz

Yes but all I want is to ignore the returning value.

But you can't. The compiler knows the code for any function called
via p returns nothing. Therefore, it can make assumptions about what
happens when such a function returns. For example, if int returns are
always done in register x, then register x will be unchanged. If
register x is used by code before and after the function call, then it
may not be necessary to reload its value.

In your case, after p=b this will no longer be true. b() changed the
value of register x but the compiler doesn't know it. It might
attempt to reuse the value of register x but now it will get the
residue from b().
And I need a function pointer to switch between the 2.

There are other techniques that don't lead to undefined behavior, such
as a wrapper function, if-then, changing a() so it always returns 0,
etc.
Hmm, maybe this would be better?

#include <stdio.h>

void a(void) {
printf("a called.\n");
}

int b(void) {
printf("b called.\n");
return 0x1;
}

static void c(void) {
b();
}

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

p = &a;

The & is superfluous.
p();
p = &c;
p();

return 0;
}
In the sense that it does not lead to undefined behavior, yes, it is
better.


<<Remove the del for email>>
 

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,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top