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.

William Xu wrote:
> Chris Dollin <> writes:
>
>> 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.

Here's why: You can convert a `void*' to or from any other
data pointer type, but you need to know what the other type is
in order to choose the proper conversion. Calling foo() or bar()
with a `void*' argument is all right, because the compiler knows
that it must convert `void*' to `char*' for foo() or convert
`void*' to `int*' for bar(). But when calling f1() -- more
precisely, when calling a function that f1 can point to --
you have told the compiler that no conversion is necessary:
an f1-addressable function takes a `void*' argument, so there
is no need to convert the `void*' that you supply. If f1
points (invalidly) at foo() or bar(), the compiler doesn't
know that it should perform a conversion.

On many machines these "conversions" are just bit-for-bit
copies of the pointers' values, but C does not require such a
simple addressing scheme and is able to run on machines whose
addressing is more intricate. So from the point of view of the
C language, you must keep the compiler properly informed about
the types of things.

Weak analogy: You know how to convert day-to-day natural
numbers to and from Roman numerals, and to and from English
utterances:

1234 <-> "MCCXXXIV"
1234 <-> "one thousand two hundred thirty-four"

Let's imagine that your bag of tricks includes C functions
to do these conversions, so you can think of them as "built-
in" like the conversions between `void*' and `double*'.

Now suppose you're writing a program that involves a few
more functions, each taking an argument representing a number
as a string. One of them wants a Roman representation, and
the other wants and English string:

What you have tried to do (the analogy approaches its
tortured conclusion; the air is thick with anticipation and
ennui) is to invent a construct that can pass `x' to either
needsRoman() or needsEnglish() without knowing which string
representation of `x' is appropriate. Can't be done: You
need to know what the called function expects to receive
before you can know how to meet its expectations.

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:

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

Old Wolf <> wrote 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.

"TomÃ¡s Ã“ hÃ‰ilidhe" <> writes:
> Old Wolf <> wrote 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) <>
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"

"Tomï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½" wrote:
> Old Wolf <> wrote 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.

On Thu, 13 Dec 2007 15:24:38 +0000, Ben Bacarisse
<> wrote:
> William Xu <> writes:
> > | 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.

Share This Page

Welcome to The Coding Forums!

Welcome to the Coding Forums, the place to chat about anything related to programming and coding languages.

Please join our friendly community by clicking the button below - it only takes a few seconds and is totally free. You'll be able to ask questions about coding or chat with the community and help others.
Sign up now!