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

typedef function with void parameters

P: n/a
This won't compile:

,----
| int foo(char *p)
| {}
|
| int main(int argc, char *argv[])
| {
| typedef int (*FUNC)(void *);
|
| FUNC f = foo;
| }
`----

The error is:

,----
| gcc -O2 /Users/william/studio/helloworlds/foo.cpp -lm -o foo
| /Users/william/studio/helloworlds/foo.cpp: In function 'int main(int, char**)':
| /Users/william/studio/helloworlds/foo.cpp:26: error: invalid conversion from 'int (*)(char*)' to 'int (*)(void*)'
`----

--
William

http://williamxu.net9.org
Dec 13 '07 #1
Share this Question
Share on Google+
13 Replies


P: n/a
William Xu wrote:
This won't compile:

,----
| int foo(char *p)
| {}
|
| int main(int argc, char *argv[])
| {
| typedef int (*FUNC)(void *);
|
| FUNC f = foo;
| }
`----

The error is:

,----
| gcc -O2 /Users/william/studio/helloworlds/foo.cpp -lm -o foo
| /Users/william/studio/helloworlds/foo.cpp: In function 'int main(int, char**)':
| /Users/william/studio/helloworlds/foo.cpp:26: error: invalid conversion from 'int (*)(char*)' to 'int (*)(void*)'
`----
So, which do you want -- a function taking a `void*` or a function taking
a `char*`? They're not compatible types. Pick one.

--
Chris "can't fit a quart into a magnetic pot" Dollin

Hewlett-Packard Limited registered office: Cain Road, Bracknell,
registered no: 690597 England Berks RG12 1HN

Dec 13 '07 #2

P: n/a
Chris Dollin <ch**********@hp.comwrites:
So, which do you want -- a function taking a `void*` or a function taking
a `char*`? They're not compatible types. Pick one.
Oh, i thought that most pointer types could be converted/stored into
void pointer. I'm trying to wrap different function pointers into FUNC,
like,

,----
| int foo(char *p){}
| int bar(int *p){}
|
| typedef int (*FUNC)(void *);
|
| FUNC f1 = foo, f2 = bar;
`----

So, this is not allowed?

--
William

http://williamxu.net9.org
Dec 13 '07 #3

P: n/a
William Xu wrote:
Chris Dollin <ch**********@hp.comwrites:
>So, which do you want -- a function taking a `void*` or a function taking
a `char*`? They're not compatible types. Pick one.

Oh, i thought that most pointer types could be converted/stored into
void pointer. I'm trying to wrap different function pointers into FUNC,
like,

,----
| int foo(char *p){}
| int bar(int *p){}
|
| typedef int (*FUNC)(void *);
|
| FUNC f1 = foo, f2 = bar;
`----

So, this is not allowed?
No - because the function types are different to the type of the
function variable.

You could perhaps force it :-

FUNC f1 = (FUNC)foo, f2 = (FUNC)bar;

But let's look at it from another angle....

If you did this and then called
f2("my dog has fleas");
what do you expect bar to receive?
Dec 13 '07 #4

P: n/a
Converting a char* to a void* is different than converting a function
that takes a char* as a parameter to a function that takes a void* as
a parameter. You're mixing up things. ;)
Dec 13 '07 #5

P: n/a
William Xu <wi*********@gmail.comwrites:
Chris Dollin <ch**********@hp.comwrites:
>So, which do you want -- a function taking a `void*` or a function taking
a `char*`? They're not compatible types. Pick one.

Oh, i thought that most pointer types could be converted/stored into
void pointer.
This is true of object pointers but not function pointers.
I'm trying to wrap different function pointers into FUNC,
like,

,----
| int foo(char *p){}
| int bar(int *p){}
|
| typedef int (*FUNC)(void *);
|
| FUNC f1 = foo, f2 = bar;
`----

So, this is not allowed?
Allowed is vague. It is a constraint violation and thus requires a
diagnostic (but that could be "I will convert these function pointers
for you" or it might be "Yuck! -- compilation halted").

If you convert (with a cast) it will work on some systems but it is
not guaranteed -- your code could break with a compiler update or even
a change in optimisation level. If you are prepared to take a chance,
always make sure that the call is though a pointer whose type matches
the type of function being called.

--
Ben.
Dec 13 '07 #6

P: n/a


William Xu wrote:
This won't compile:

,----
| int foo(char *p)
| {}
You've declared your function as returning an 'int', and then failed
to return anything. gcc will warn about these things; you should turn
the warning on. I normally use

gcc -ansi -pedantic -Wall -Wpointer-arith -Wcast-align -Wwrite-strings
-Wstrict-prototypes -Wmissing-prototypes
| int main(int argc, char *argv[])
| {
| typedef int (*FUNC)(void *);
|
| FUNC f = foo;
While it's no longer strictly necessary, I still think it's good
discipline to explicitly return a value from main(), too.
| }
`----

The error is:

,----
| gcc -O2 /Users/william/studio/helloworlds/foo.cpp -lm -o foo
| /Users/william/studio/helloworlds/foo.cpp: In function 'int main(int, char**)':
| /Users/william/studio/helloworlds/foo.cpp:26: error: invalid conversion from 'int (*)(char*)' to 'int (*)(void*)'
`----
It's perfectly legal to request that conversion, but it is not a
conversion that will occur implicitly. You have to perform an explicit
cast.

Note: the ONLY thing you can usefully do with the value of 'f' after
the conversion is convert it back to the original type, and then use
the restored function pointer to call the function. Here's a corrected
version:

int foo(char *p)
{ return 0; }

int main(int argc, char *argv[])
{
typedef int (*FUNC)(void *);

FUNC f = (FUNC)foo;

int (*g)(char*) = (int (*)(char*))f;
return g(argv[0]);
}
Dec 13 '07 #7

P: n/a
ja*********@verizon.net writes:
You've declared your function as returning an 'int', and then failed
to return anything. gcc will warn about these things; you should turn
the warning on. I normally use

gcc -ansi -pedantic -Wall -Wpointer-arith -Wcast-align -Wwrite-strings
-Wstrict-prototypes -Wmissing-prototypes
[...]
While it's no longer strictly necessary, I still think it's good
discipline to explicitly return a value from main(), too.
Thanks. I'll be more careful before posting next time.
It's perfectly legal to request that conversion, but it is not a
conversion that will occur implicitly. You have to perform an explicit
cast.

Note: the ONLY thing you can usefully do with the value of 'f' after
the conversion is convert it back to the original type, and then use
the restored function pointer to call the function.
You are right. This seems an awkward usage, though.

I realize the better way is to learn from `qsort' function. Define a
common function pointer interface, implement(especially casting
correctly) it case by case.

I did an exercise:

---------------------------------8<-------------------------------------
#include <stdlib.h>
#include <stdio.h>

void print_any(void *any, void(*print)(void *p))
{
print(any);
}

void print_str(void *p)
{
printf("%s\n", (char*)p);
}

void print_int(void *p)
{
printf("%d\n", *(int*)p);
}

int main(int argc, char *argv[])
{
char *p = "hi";
int n = 2;

print_any(p, print_str);
print_any( & n, print_int);

return 0;
}
---------------------------------8<-------------------------------------

--
William

http://williamxu.net9.org
Dec 13 '07 #8

P: n/a
William Xu <wi*********@gmail.comwrote in comp.lang.c:
,----
| int foo(char *p)
| {}
|
| int main(int argc, char *argv[])
| {
| typedef int (*FUNC)(void *);
|
| FUNC f = foo;
| }

char* and void* are identical in how they work, i.e. their size and how
they store a given address as a bit pattern, but they're not the same
type as far as the compiler's concerned.

You can get your code to work with:

FUNC f = (int(*)(void*))foo;

and its behaviour will be well-defined, but you should probably rethink
your design. What are you gonna do when you come up against a pointer
type that's smaller than a void*? An int* for example?

--
Toms hilidhe
Dec 13 '07 #9

P: n/a
On Dec 14, 7:06 am, "Toms hilidhe" <t...@lavabit.comwrote:
William Xu <william....@gmail.comwrote in comp.lang.c:
| int foo(char *p)
| {}
|
| int main(int argc, char *argv[])
| {
| typedef int (*FUNC)(void *);
|
| FUNC f = foo;
| }

You can get your code to work with:

FUNC f = (int(*)(void*))foo;

and its behaviour will be well-defined
It wouldn't be well-defined to call the function
through f, however.
Dec 13 '07 #10

P: n/a
Old Wolf <ol*****@inspire.net.nzwrote in comp.lang.c:
>You can get your code to work with:

FUNC f = (int(*)(void*))foo;

and its behaviour will be well-defined

It wouldn't be well-defined to call the function
through f, however.

Given that char* and void* have identical representation, do you not think
it would be OK?

I'm not contesting what you said, I just want to see what people think
about it.

My thoughts presently are that I can't fathom why it could fail if char*
and void* are the same.

--
Toms hilidhe
Dec 14 '07 #11

P: n/a
"Tomás Ó hÉilidhe" <to*@lavabit.comwrites:
Old Wolf <ol*****@inspire.net.nzwrote in comp.lang.c:
>>You can get your code to work with:

FUNC f = (int(*)(void*))foo;

and its behaviour will be well-defined

It wouldn't be well-defined to call the function
through f, however.

Given that char* and void* have identical representation, do you not think
it would be OK?

I'm not contesting what you said, I just want to see what people think
about it.

My thoughts presently are that I can't fathom why it could fail if char*
and void* are the same.
Well, it can fail because the standard doesn't define the behavior of
such a call.

Realistically, I'd expect it to work under most, perhaps all,
real-world implementations. But I can easily imagine an
implementation that associates type information with function
pointers, and *deliberately* traps on such a call. Such an
implementation would likely impose some overhead on all indirect
function calls, but it would catch errors (defined, in this context,
as constructs whose behavior is not defined by the standard) than a
more traditional implementation would.

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Looking for software development work in the San Diego area.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Dec 14 '07 #12

P: n/a
"Tom��������������� ���������������� " wrote:
Old Wolf <ol*****@inspire.net.nzwrote in comp.lang.c:
>>You can get your code to work with:

FUNC f = (int(*)(void*))foo;

and its behaviour will be well-defined

It wouldn't be well-defined to call the function
through f, however.


Given that char* and void* have identical representation, do you not
think it would be OK?
There's a footnote somewhere in the Standard (I'm too lazy
to look it up at the moment) to the effect that the identical
representations are "intended" to allow interchangeability in
things like function calls. But a statement of intent is a
hint to the implementor, not a requirement that must be fulfilled;
footnotes are non-normative.
I'm not contesting what you said, I just want to see what people think
about it.

My thoughts presently are that I can't fathom why it could fail if char*
and void* are the same.
Nothing in the Standard forbids the use of different parameter-
passing mechanisms for `void*' and `char*', even though they share
the same representation. Maybe the machine has a repertoire of
string instructions that use "implied" registers, so the code is
optimized by passing a `char*' argument in one of these special-
purpose registers while using other general-purpose registers for
other arguments, including `void*'. If the caller passes its
`void*' argument in R1 and the callee tries to retrieve a `char*'
parameter from R0, "bit happens."

I don't know of any machines that use such a calling convention,
but there are a *lot* of machines I don't know, and there certainly
*are* machines whose string instructions use implied registers. The
idea may be odd, but it's not completely outlandish. The C Standard
goes to some lengths to permit implementations on peculiar machines,
recognizing that this is a fashion-driven industry and today's oddity
is tomorrow's must-have.

--
Eric Sosman
es*****@ieee-dot-org.invalid
Dec 14 '07 #13

P: n/a
On Thu, 13 Dec 2007 15:24:38 +0000, Ben Bacarisse
<be********@bsb.me.ukwrote:
William Xu <wi*********@gmail.comwrites:
| int foo(char *p){}
| int bar(int *p){}
|
| typedef int (*FUNC)(void *);
|
| FUNC f1 = foo, f2 = bar;
So, this is not allowed?

Allowed is vague. It is a constraint violation and thus requires a
diagnostic (but that could be "I will convert these function pointers
for you" or it might be "Yuck! -- compilation halted").
Right. Although I am a bit surprised that the OP's version of gcc
defaults the diagnostic to an error; mine make it a warning.
If you convert (with a cast) it will work on some systems but it is
not guaranteed -- your code could break with a compiler update or even
a change in optimisation level. If you are prepared to take a chance,
always make sure that the call is though a pointer whose type matches
the type of function being called.
_If_ you convert back to the correct (func pointer) type before
calling, it IS guaranteed to work. (Converting to and) calling through
the wrong pointer pointer is not guaranteed, and indeed could break,
although I'd be surprised if optimization does so -- C is usually and
traditionally implemented with separate compilation and linking, for
which optimization that doesn't eliminate a call entirely (inlining)
can usually change calling conventions only in very limited ways.

- formerly david.thompson1 || achar(64) || worldnet.att.net
Dec 24 '07 #14

This discussion thread is closed

Replies have been disabled for this discussion.