typedef Used to Cast Function Pointers

  • Thread starter Barbrawl McBribe
  • Start date
B

Barbrawl McBribe

Is is possible to use typedefs to cast function pointers? I think I
saw this in the WINGs src; grep for '(hashFunc)'. So far, trying to
use a typedef to cast function pointers so that a return value of
float is changed to float seems not to work; I belive it was like
this:

typedef int (*foo) (int);

function_ptr_bar = (foo)function_that_returns_float;
 
K

Kevin Goodsell

Barbrawl said:
Is is possible to use typedefs to cast function pointers?

Only a cast expression can be used to cast.
I think I
saw this in the WINGs src; grep for '(hashFunc)'. So far, trying to
use a typedef to cast function pointers so that a return value of
float is changed to float seems not to work; I belive it was like
this:

typedef int (*foo) (int);

This declares foo as an alias for type "pointer to function taking 1
argument of type int and returning int".
function_ptr_bar = (foo)function_that_returns_float;

This uses a cast expression to convert from one type to another. I don't
believe you can safely call the function through the resulting pointer
unless it is first cast back to the correct type.

-Kevin
 
K

Keith Thompson

Is is possible to use typedefs to cast function pointers? I think I
saw this in the WINGs src; grep for '(hashFunc)'. So far, trying to
use a typedef to cast function pointers so that a return value of
float is changed to float seems not to work; I belive it was like
this:

typedef int (*foo) (int);

function_ptr_bar = (foo)function_that_returns_float;

I presume you mean "so that a return value of float is changed to
int".

Why would you want to do this? You can probably make it work, but
it's extremely unsafe and non-portable. Basically, you're trying to
lie to the compiler. At best, you'll call function_that_returns_float()
and treat its result as an int (not a numeric conversion, but a
reinterpretation of the bits). At worst, the calling conventions will
differ, and arbitrarily bad things will happen, from getting
meaningless garbage to crashing your program.
 
A

Al Bowers

Keith said:
I presume you mean "so that a return value of float is changed to
int".

Why would you want to do this? You can probably make it work, but
it's extremely unsafe and non-portable. Basically, you're trying to
lie to the compiler. At best, you'll call function_that_returns_float()
and treat its result as an int (not a numeric conversion, but a
reinterpretation of the bits). At worst, the calling conventions will
differ, and arbitrarily bad things will happen, from getting
meaningless garbage to crashing your program.

The Standard explicitly calls it Undefined Behavior.

From 6.3.2.3.8
"A pointer to a function of one type may be converted to
a pointer to a function of another type and back again;
the result shall compare equal to the original pointer.
If a converted pointer is used to call a function whose
type is not compatible with the pointed-to type, the
behavior is undefined."
 
K

Kevin Goodsell

Al said:
The Standard explicitly calls it Undefined Behavior.

From 6.3.2.3.8
"A pointer to a function of one type may be converted to
a pointer to a function of another type and back again;
the result shall compare equal to the original pointer.
If a converted pointer is used to call a function whose
type is not compatible with the pointed-to type, the
behavior is undefined."

Question: In what ways could the function types be different, and still
be compatible? I'm guessing it's safe if the conversion adds const
and/or volatile qualifiers to some parameters. Could you replace a void*
parameter with a char* parameter? A signed integer with an unsigned
integer? What if the real function returns a value, but the pointer it's
called through is to a void function type?

I have my suspicions about the answers to these questions, but I'd like
to know if I'm wrong.

-Kevin
 
L

Les Cargill

Kevin said:
Question: In what ways could the function types be different, and still
be compatible? I'm guessing it's safe if the conversion adds const
and/or volatile qualifiers to some parameters. Could you replace a void*
parameter with a char* parameter? A signed integer with an unsigned
integer? What if the real function returns a value, but the pointer it's
called through is to a void function type?

I have my suspicions about the answers to these questions, but I'd like
to know if I'm wrong.

On the level of the source code being considered correct, they cannot be
different.

On the level of executing undefined behavior in a not-pernicious
manner, whenever nothing happens that would cause execution to halt - like
when the shape of the parameters are the same. You could mix up
ints, longs and pointers on some architectures.

But it's still wrong :)
 
B

Barbrawl McBribe

Keith Thompson said:
I presume you mean "so that a return value of float is changed to
int".

Yes. This is just messing around; I deem it has no practical
application.
Why would you want to do this?

It's a CS thing... Personally, I just want to try what I can, and I
will learn from even stupid sh*t. Remember, as Carl Sagan said, that
fundamental science can be a prerequisite for applied science.

You can probably make it work, but
it's extremely unsafe and non-portable.

Definitely...

Basically, you're trying to
lie to the compiler.

That's a clever way of saying it.

At best, you'll call function_that_returns_float()
and treat its result as an int (not a numeric conversion, but a
reinterpretation of the bits). At worst, the calling conventions will
differ, and arbitrarily bad things will happen, from getting
meaningless garbage to crashing your program.

Well, the casts in the WINGs source are casting to what the function
*was* in the first place, if you see what I mean (as in from a return
value of void * to void * and likewise for the arguments). I
eliminated them, recompiled, and all was well. I can conclude
reasonably that they are there for clarity.
 
D

Dave Thompson

Question: In what ways could the function types be different, and still
be compatible? I'm guessing it's safe if the conversion adds const
and/or volatile qualifiers to some parameters. Could you replace a void*
parameter with a char* parameter? A signed integer with an unsigned
integer? What if the real function returns a value, but the pointer it's
called through is to a void function type?
Two *prototyped* function types are compatible (only) if corresponding
parameters are compatible ignoring top-level qualification and after
"adjustment" to pointer of (declared) array or function parameters,
and both or neither end with ellipsis (variadic). void* and char* are
not compatible according to the type rules, although they are required
to have the same representation and so substituting them will work in
practice unless the implementation is odd (or perverse) enough to pass
them differently, and the same for corresponding signed and unsigned
integers. Including plain/signed/unsigned char, and pointers thereto.

An incomplete or "forward declared" struct or union is compatible with
the completed type, and (nearly) identically declared such types or
enums in different t.u.s are compatible although formally they are not
the same type. An enum is compatible with an implementation-defined
integer type, usually int. Array of unspecified (or in C99 VLA) bound
is compatible (at compile time) with array of fixed bound. I think
that's all the freedom you officially have.

The more complicated cases are compatibility between or with
unprototyped function types, e.g.:
int foo (int x, double y);
int foo (x, y) short x; float y; { blah blah }
are compatible, and a pointer to unspecified-args function:
int (*ptr)() = foo;
can be silently converted from any function pointer, but can correctly
be used to call only a function with no arguments (and returning int).
For unprototyped definitions, the void*-char* and signed-unsigned
cases are permitted in 6.5.2.2, which is more detailed than 6.3.3.8.

Both prototyped and unprototyped declarations (and definitions) of a
function do define the return type, and (so) function types with
different return types are never compatible.


- David.Thompson1 at worldnet.att.net
 
K

Keith Thompson

Well, the casts in the WINGs source are casting to what the function
*was* in the first place, if you see what I mean (as in from a return
value of void * to void * and likewise for the arguments). I
eliminated them, recompiled, and all was well. I can conclude
reasonably that they are there for clarity.

Hmm. I don't know what WINGs might be, but simply casting a function
to its own type isn't going to do anything for clarity. On the
contrary, it's confusing and error-prone. Rather than letting the
compiler verify the function type, the cast forces the compiler to
assume that it's of the right type and inhibits error checks.

*Unless* it's casting function pointers to their proper types. I can
imagine a program keeping function pointers of various types in a data
structure, where each element stores a function pointer (cast to some
generic function pointer type) and an indication of the function's
actual type. A calling routine would then cast the function pointer
back to its original type. Something like that might be used in an
interpreter, for example.

It's something you might consider if you *really* know what you're
doing.
 
D

Dave Thompson

The more complicated cases are compatibility between or with
unprototyped function types, e.g.:
int foo (int x, double y);
int foo (x, y) short x; float y; { blah blah }
are compatible, and a pointer to unspecified-args function:
int (*ptr)() = foo;
can be silently converted from any function pointer, but can correctly
be used to call only a function with no arguments (and returning int).

Of course it can be used to call any oldstyle definition, or one with
prototyped parameter types not altered by the default promotions and
not variadic. But (in either case) they do have to return int.

- David.Thompson1 at worldnet.att.net
 
B

Barbrawl McBribe

Keith Thompson said:
Hmm. I don't know what WINGs might be

If you are familiar with the X Window System, it's a toolkit for the
same associated w/ the WindowMaker window manager.

but simply casting a function
to its own type isn't going to do anything for clarity. On the
contrary, it's confusing and error-prone. Rather than letting the
compiler verify the function type, the cast forces the compiler to
assume that it's of the right type and inhibits error checks.

That makes sense.
*Unless* it's casting function pointers to their proper types. I can
imagine a program keeping function pointers of various types in a data
structure, where each element stores a function pointer (cast to some
generic function pointer type) and an indication of the function's
actual type. A calling routine would then cast the function pointer
back to its original type. Something like that might be used in an
interpreter, for example.

Eh?? Well, this is for hash table utility functions in the graphics
toolkit.
It's something you might consider if you *really* know what you're
doing.

Seems risky and evidently a lot of the behavior is undefined.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top