Baffled by this ... (casting of function pointers)

Discussion in 'C Programming' started by Alfonso Morra, Aug 26, 2005.

  1. How can this work ?

    I have the following declarations in a header:

    Header
    =========
    typedef void (*VFPTR)(void) ;
    void FOO_Callback(void*, char*, char*, int, unsigned long, void*,void*);
    int bar(int *, char *, VFPTR, void *);

    Source
    =========
    In the C source code, I come accross this line:

    bar(&id, name, FOO_Callback, (void *)handle);

    This compiles without any problems when compiling as a C program. When
    compiling as a C++ source (stricter type checking etc) - the compiler
    (unsuprisingly) threw a wobbly. I had to add an explicit "C-style" cast
    as ff:

    bar(&id, name, (VOID_FUNC)FOO_Callback, (void *)handle);

    and the compiler was happy once again.

    BUT - wait a minute, HOW can a function (FOO_Callback) declared as a
    function returning void and accepting several arguments, be "coerced"
    into a function that accepts no arguments?

    Here are my questions:

    1). Ok it compiles - but does it make sense?
    2). Are there any conditions under which one may coerce a function that
    requires arguments into one not taking arguments?
    3). What does it mean to call a function that expects arguments, with no
    arguments - will it even work ?


    I hope someone can shed somelight on this baffling piece of "sleight of
    hand".
     
    Alfonso Morra, Aug 26, 2005
    #1
    1. Advertising

  2. On Fri, 26 Aug 2005 00:42:00 +0000 (UTC), Alfonso Morra
    <> wrote:

    >How can this work ?
    >
    >I have the following declarations in a header:
    >
    >Header
    >=========
    >typedef void (*VFPTR)(void) ;
    >void FOO_Callback(void*, char*, char*, int, unsigned long, void*,void*);
    >int bar(int *, char *, VFPTR, void *);
    >
    >Source
    >=========
    >In the C source code, I come accross this line:
    >
    >bar(&id, name, FOO_Callback, (void *)handle);


    The cast on handle is superfluous if it is a pointer of any type.
    Since the prototype for bar is known, any pointer type will be
    implicitly converted void* as part of evaluating the arguments.

    >
    >This compiles without any problems when compiling as a C program. When


    Since you should have received a diagnostic on the third argument, you
    may have discovered an error in your compiler. It is also possible
    that you need to raise the warning level or disable some language
    extension.

    >compiling as a C++ source (stricter type checking etc) - the compiler
    >(unsuprisingly) threw a wobbly. I had to add an explicit "C-style" cast
    >as ff:
    >
    >bar(&id, name, (VOID_FUNC)FOO_Callback, (void *)handle);


    I assume you meant (VFPTR) as your cast.

    >
    >and the compiler was happy once again.
    >
    >BUT - wait a minute, HOW can a function (FOO_Callback) declared as a
    >function returning void and accepting several arguments, be "coerced"
    >into a function that accepts no arguments?


    A cast is capable of coercing quite a few things, as far as compiler
    syntax checking goes. Whether the code will work after the cast is a
    completely different issue. Since bar thinks the argument is pointer
    to a function taking no arguments, that is how bar would call the
    function. When FOO_Callback actually gets control, it will look for
    the four arguments and you will invoke undefined behavior.

    >
    >Here are my questions:
    >
    >1). Ok it compiles - but does it make sense?


    No.

    >2). Are there any conditions under which one may coerce a function that
    >requires arguments into one not taking arguments?


    Only if you never call it. Possibly if you can guarantee the
    function will not attempt to look at the arguments.

    >3). What does it mean to call a function that expects arguments, with no
    >arguments - will it even work ?


    Undefined behavior.

    >
    >
    >I hope someone can shed somelight on this baffling piece of "sleight of
    >hand".


    Sleight of hand implies some skill as a magician. This is just sloppy
    code.


    <<Remove the del for email>>
     
    Barry Schwarz, Aug 26, 2005
    #2
    1. Advertising

  3. Alfonso Morra

    Jack Klein Guest

    On Fri, 26 Aug 2005 00:42:00 +0000 (UTC), Alfonso Morra
    <> wrote in comp.lang.c:

    > How can this work ?
    >
    > I have the following declarations in a header:
    >
    > Header
    > =========
    > typedef void (*VFPTR)(void) ;
    > void FOO_Callback(void*, char*, char*, int, unsigned long, void*,void*);
    > int bar(int *, char *, VFPTR, void *);
    >
    > Source
    > =========
    > In the C source code, I come accross this line:
    >
    > bar(&id, name, FOO_Callback, (void *)handle);
    >
    > This compiles without any problems when compiling as a C program. When
    > compiling as a C++ source (stricter type checking etc) - the compiler
    > (unsuprisingly) threw a wobbly. I had to add an explicit "C-style" cast
    > as ff:


    The fact that it compiles as a C program indicates one of two things.
    The first is that your compiler could be broken. The second, and more
    likely, is that your are not operating your compiler in conforming
    mode, and it is accepting this as some sort of compiler specific
    non-standard extension.

    The code is just as illegal in C as it is in C++. Without the cast, a
    conforming compiler must issue a diagnostic.

    > bar(&id, name, (VOID_FUNC)FOO_Callback, (void *)handle);
    >
    > and the compiler was happy once again.
    >
    > BUT - wait a minute, HOW can a function (FOO_Callback) declared as a
    > function returning void and accepting several arguments, be "coerced"
    > into a function that accepts no arguments?


    The C standard specifically allows a pointer to a function of one type
    to be converted to a pointer to a function of another type, with a
    suitable cast. If the result is later converted back to the original
    pointer type, again by the appropriate cast, the reconverted pointer
    is guaranteed to point to the original function. So with the cast, it
    is perfectly legal in C and, even though it's off-topic here, in C++.
    Without the cast it is illegal in both languages.

    > Here are my questions:
    >
    > 1). Ok it compiles - but does it make sense?


    With the cast, yes.

    > 2). Are there any conditions under which one may coerce a function that
    > requires arguments into one not taking arguments?


    With the cast, yes.

    > 3). What does it mean to call a function that expects arguments, with no
    > arguments - will it even work ?


    If you call a function through a function pointer of the wrong type,
    the behavior is undefined. As far as the language is concerned, there
    is no longer a definition of "work" in existence once you produce
    undefined behavior.

    > I hope someone can shed somelight on this baffling piece of "sleight of
    > hand".


    There are times when it is useful to deal with generic pointers in C.
    A pointer to any type of object can be converted to pointer to void
    and back to a pointer of the original type, and will still point to
    the original object.

    But there is no conversion at all defined between pointers to
    functions and any type of pointer to object, not even pointer to void.
    Object and function pointers do not exist on the same planet, and
    can't be mixed.

    So it is quite common to use void(*func)(void) as a generic pointer to
    function. As long as the pointer is converted back to the proper type
    and called with the correct number and type of arguments, the behavior
    is well-defined.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Aug 26, 2005
    #3
  4. Alfonso Morra wrote:

    > How can this work ?
    >
    > I have the following declarations in a header:
    >
    > Header
    > =========
    > typedef void (*VFPTR)(void) ;
    > void FOO_Callback(void*, char*, char*, int, unsigned long, void*,void*);
    > int bar(int *, char *, VFPTR, void *);
    >
    > Source
    > =========
    > In the C source code, I come accross this line:
    >
    > bar(&id, name, FOO_Callback, (void *)handle);
    >
    > This compiles without any problems when compiling as a C program. When
    > compiling as a C++ source (stricter type checking etc) - the compiler
    > (unsuprisingly) threw a wobbly. I had to add an explicit "C-style" cast
    > as ff:
    >
    > bar(&id, name, (VOID_FUNC)FOO_Callback, (void *)handle);
    >
    > and the compiler was happy once again.
    >
    > BUT - wait a minute, HOW can a function (FOO_Callback) declared as a
    > function returning void and accepting several arguments, be "coerced"
    > into a function that accepts no arguments?
    >
    > Here are my questions:
    >
    > 1). Ok it compiles - but does it make sense?
    > 2). Are there any conditions under which one may coerce a function that
    > requires arguments into one not taking arguments?
    > 3). What does it mean to call a function that expects arguments, with no
    > arguments - will it even work ?
    >
    >
    > I hope someone can shed somelight on this baffling piece of "sleight of
    > hand".
    >

    Anyone care to add a third view? - I'm none the wiser here since the two
    responses I received contradict each other...
     
    Alfonso Morra, Aug 26, 2005
    #4
  5. On Thu, 25 Aug 2005 20:43:33 -0700, Barry Schwarz wrote:

    > On Fri, 26 Aug 2005 00:42:00 +0000 (UTC), Alfonso Morra
    > <> wrote:
    >
    >>How can this work ?
    >>
    >>I have the following declarations in a header:
    >>
    >>Header
    >>=========
    >>typedef void (*VFPTR)(void) ;
    >>void FOO_Callback(void*, char*, char*, int, unsigned long, void*,void*);
    >>int bar(int *, char *, VFPTR, void *);
    >>
    >>Source
    >>=========
    >>In the C source code, I come accross this line:
    >>
    >>bar(&id, name, FOO_Callback, (void *)handle);

    >
    > The cast on handle is superfluous if it is a pointer of any type.
    > Since the prototype for bar is known, any pointer type will be
    > implicitly converted void* as part of evaluating the arguments.


    Only pointers to unqualified object or imcomplete types can be converted
    implicitly to void *. Function pointers can't nor can pointers with types
    like const int * or indeed const void *. However this is a good thing and
    attempts at conversions like these should be warned about so the code is
    much better without the cast.

    Lawrence
     
    Lawrence Kirby, Aug 26, 2005
    #5
  6. On Fri, 26 Aug 2005 09:22:10 +0000, Alfonso Morra wrote:

    >
    >
    > Alfonso Morra wrote:
    >
    >> How can this work ?
    >>
    >> I have the following declarations in a header:
    >>
    >> Header
    >> =========
    >> typedef void (*VFPTR)(void) ;
    >> void FOO_Callback(void*, char*, char*, int, unsigned long, void*,void*);
    >> int bar(int *, char *, VFPTR, void *);
    >>
    >> Source
    >> =========
    >> In the C source code, I come accross this line:
    >>
    >> bar(&id, name, FOO_Callback, (void *)handle);
    >>
    >> This compiles without any problems when compiling as a C program. When
    >> compiling as a C++ source (stricter type checking etc) - the compiler
    >> (unsuprisingly) threw a wobbly. I had to add an explicit "C-style" cast
    >> as ff:
    >>
    >> bar(&id, name, (VOID_FUNC)FOO_Callback, (void *)handle);
    >>
    >> and the compiler was happy once again.
    >>
    >> BUT - wait a minute, HOW can a function (FOO_Callback) declared as a
    >> function returning void and accepting several arguments, be "coerced"
    >> into a function that accepts no arguments?


    You can cast pointer types, but ultimately when you call a function the
    arguments you call it with must be compatible with its definition.
    Essentially that means if you cast a function pointer to a different
    function pointer type you must cast it back again before calling the
    function.

    >> Here are my questions:
    >>
    >> 1). Ok it compiles - but does it make sense?


    No, you're calling the function with the wrong number of arguments, this
    has undefined behaviour i.e. the behaviour of your entire program ceases
    to be well defined.

    >> 2). Are there any conditions under which one may coerce a function that
    >> requires arguments into one not taking arguments?


    Remember you are not "coercing" functions but pointers to functions. As
    noted above you can do this but you must convert the pointer back again
    before you call the function.

    >> 3). What does it mean
    >> to call a function that expects arguments, with no arguments - will it
    >> even work ?


    Undefined behaviour means anything can happen. It might "work" to some
    degree, it might fail completely, you get no guarantees either way.

    >> I hope someone can shed somelight on this baffling piece of "sleight of
    >> hand".


    The code is simply broken.

    > Anyone care to add a third view? - I'm none the wiser here since the two
    > responses I received contradict each other...


    How so?

    Lawrence
     
    Lawrence Kirby, Aug 26, 2005
    #6
  7. Lawrence Kirby wrote:
    > On Fri, 26 Aug 2005 09:22:10 +0000, Alfonso Morra wrote:
    >
    >
    >>
    >>Alfonso Morra wrote:
    >>
    >>
    >>>How can this work ?
    >>>
    >>>I have the following declarations in a header:
    >>>
    >>>Header
    >>>=========
    >>>typedef void (*VFPTR)(void) ;
    >>>void FOO_Callback(void*, char*, char*, int, unsigned long, void*,void*);
    >>>int bar(int *, char *, VFPTR, void *);
    >>>
    >>>Source
    >>>=========
    >>>In the C source code, I come accross this line:
    >>>
    >>>bar(&id, name, FOO_Callback, (void *)handle);
    >>>
    >>>This compiles without any problems when compiling as a C program. When
    >>>compiling as a C++ source (stricter type checking etc) - the compiler
    >>>(unsuprisingly) threw a wobbly. I had to add an explicit "C-style" cast
    >>>as ff:
    >>>
    >>>bar(&id, name, (VOID_FUNC)FOO_Callback, (void *)handle);
    >>>
    >>>and the compiler was happy once again.
    >>>
    >>>BUT - wait a minute, HOW can a function (FOO_Callback) declared as a
    >>>function returning void and accepting several arguments, be "coerced"
    >>>into a function that accepts no arguments?

    >
    >
    > You can cast pointer types, but ultimately when you call a function the
    > arguments you call it with must be compatible with its definition.
    > Essentially that means if you cast a function pointer to a different
    > function pointer type you must cast it back again before calling the
    > function.
    >
    >
    >>>Here are my questions:
    >>>
    >>>1). Ok it compiles - but does it make sense?

    >
    >
    > No, you're calling the function with the wrong number of arguments, this
    > has undefined behaviour i.e. the behaviour of your entire program ceases
    > to be well defined.
    >
    >
    >>>2). Are there any conditions under which one may coerce a function that
    >>>requires arguments into one not taking arguments?

    >
    >
    > Remember you are not "coercing" functions but pointers to functions. As
    > noted above you can do this but you must convert the pointer back again
    > before you call the function.
    >
    >
    >>>3). What does it mean
    >>>to call a function that expects arguments, with no arguments - will it
    >>>even work ?

    >
    >
    > Undefined behaviour means anything can happen. It might "work" to some
    > degree, it might fail completely, you get no guarantees either way.
    >
    >
    >>>I hope someone can shed somelight on this baffling piece of "sleight of
    >>>hand".

    >
    >
    > The code is simply broken.
    >
    >
    >>Anyone care to add a third view? - I'm none the wiser here since the two
    >>responses I received contradict each other...

    >
    >
    > How so?
    >
    > Lawrence
    >


    Thanks Lawrence, your posyt clarifies things up. BTW, I posted my
    "request for disambiguation" before your last post (i.e. only Barry and
    Jack had responded, and they each had a different P.O.V).

    What you've said so far ties in with what Jack says - and it does stand
    to reason if one pauses to think carefully at what is actually been done.
     
    Alfonso Morra, Aug 26, 2005
    #7
  8. Alfonso Morra

    Denis Kasak Guest

    Alfonso Morra wrote:
    >
    > Thanks Lawrence, your posyt clarifies things up. BTW, I posted my
    > "request for disambiguation" before your last post (i.e. only Barry and
    > Jack had responded, and they each had a different P.O.V).
    >
    > What you've said so far ties in with what Jack says - and it does stand
    > to reason if one pauses to think carefully at what is actually been done.


    Actually, all three posters (Barry, Jack and Lawrence) have told you the
    same thing. They all stated that you must change the pointer back before
    calling the function through it and that failing to do so invokes
    undefined behaviour. Why would you think Barry said something different?

    -- Denis
     
    Denis Kasak, Aug 26, 2005
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Lloyd Dupont

    baffled...

    Lloyd Dupont, Sep 1, 2004, in forum: ASP .Net
    Replies:
    2
    Views:
    1,231
    Lloyd Dupont
    Sep 2, 2004
  2. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    680
  3. Alastair Thompson
    Replies:
    1
    Views:
    151
  4. Alastair Thompson
    Replies:
    0
    Views:
    116
    Alastair Thompson
    Apr 25, 2013
  5. Peter Otten
    Replies:
    3
    Views:
    131
    Steven D'Aprano
    Apr 27, 2013
Loading...

Share This Page