1. This forum section is a read-only archive which contains old newsgroup posts. If you wish to post a query, please do so in one of our main forum sections (here). This way you will get a faster, better response from the members on Motherboard Point.

Casting function pointers

Discussion in 'Embedded' started by KKL, Jan 30, 2008.

  1. KKL

    KKL Guest

    I wonder how casting with function pointers work, how it "should be"
    handled and how it "should not be" handled. Can anyone tell whether
    the below code should work or not?

    Module: Task Service Abstraction Layer
    int taskCreate(char* taskName, void* funcPtr, int
    taskPriority,..........)
    {
    myTaskStructure TaskProperties;
    int TaskId, errStatus;

    ............
    //Casting void* funcPtr to function pointer that returns void and
    accepts no arguments
    TaskProperties.entryPtr = (void ()(void)* ) funcPtr;
    errStatus = rtosTaskCreate( taskName, &TaskProperties, &TaskId);

    .........
    }

    Module: SomeClass.cpp

    void someClass::taskLoop( int taskArgument)
    {
    ........
    }

    void somClass::initialize( void )
    {

    taskCreate( "Task1", (void* )&taskLoop, 25,.....);
    }

    Module: SomeOtherClass.cpp

    int myTaskEntryReturnsInt( void )
    {

    }

    SomeOtherClass::initialize( void )
    {
    taskCreate( "Task2", (void* )&myTaskEntryReturnsInt, 30,.....);
    }

    Module: AnotherClass.cpp
    void myTaskEntryTakesInt( int TaskArg )
    {

    }

    AnotherClass::initialize( void )
    {
    taskCreate( "Task3", (void* )&myTaskEntryTakesInt, 40,.....);
    }

    My question is whether these kind of casting for function pointers is
    valid. If valid should it work with a predictable behavior or the
    behavior is undefined.
     
    KKL, Jan 30, 2008
    #1
    1. Advertisements

  2. KKL

    Arlet Guest

    Why ?

    The example makes no sense. If your task mechanism doesn't support
    tasks returning/accepting any kind of value, then why bother declaring
    your task entries as functions that do so ?

    Just declare your task entries as

    void myTaskEntry( void )

    And use:

    int taskCreate(char* taskName, void (*funcPtr)( void), ...

    No casts are required that way, and the compiler will be able to
    verify pointer types for you.
     
    Arlet, Jan 30, 2008
    #2
    1. Advertisements

  3. No it is not. There is plenty of mistakes in your example. The first
    one: you can't cast a class member function to an ordinary function.


    Vladimir Vassilevsky
    DSP and Mixed Signal Design Consultant
    http://www.abvolt.com
     
    Vladimir Vassilevsky, Jan 30, 2008
    #3
  4. [example casting various member functions to task functions snipped]

    1) You have to pass a compatible function pointer to the "TaskCreate"
    function. Frequently this will be "void TaskType(void *arg)" or something
    like "int TaskType(void *arg)". Some OSes might have additional parameters
    but generally void * is enough. You generally can't cast a function pointer
    to a different one, especially if the argument list is different, since the
    stack will probably get misaligned or the arguemnts will get passed in the
    wrong registers.

    2) Member functions in C++ take the hidden "this" point argument so you can
    never pass them to general "TaskCreate" type functions unless the OS knows
    about the base class of your class.

    What I usually do is this:

    class ActiveClass
    {
    protected:
    static void ThreadStarter(void *arg) { ((ActiveClass
    *)arg)->ThreadProc(); }
    void ThreadProc()
    {
    while (1)
    {
    DoTaskStuff();
    }
    }

    public:
    int Start() { TaskCreate(ThreadStarter, this); } // assumption: second
    argument is what's passed to "arg"
    };


    The important thing is that ThreadStarter is static, which turns it into a
    normal non-member function and that arg is cast to the type of the class
    that has the member function with the task handling.

    There are various ways of generalizing this approach with templates. You can
    also pull out the ThreadStarter into a function outside of the class but I
    like bundling things together as shown.

    Andrew
     
    andrew queisser, Jan 30, 2008
    #4
  5. That's actually quite simply: it "should not" be handled at all.

    Whenever you think you should cast a function pointer, the probability
    is very high that you're trying to do the wrong thing, so it's generally
    best to not do it at all.

    The only safe casts involving function pointers are those to other
    function pointer types --- and that only if you cast back to the
    original type before actually using the pointer to call the function.
    But if you must eventually go back to the original type anyway, what
    would be the point of casting in the first place?
    This is an invitation for disaster. Function pointers and data pointers
    don't mix. Not even if the data pointers are (void *).

    And on top of that, your function pointer cast looks syntactically
    wrong. It should be (void (*)(void)).
     
    Hans-Bernhard Bröker, Jan 30, 2008
    #5
  6. Le Wed, 30 Jan 2008 10:46:26 -0800, KKL a écrit:
    (void ()(void)* ) funcPtr does not make any sense.
    Is your code compiles ? No offense, If so i wish you good luck (and
    therefore to those who work with you)
     
    Habib Bouaziz-Viallet, Jan 31, 2008
    #6
  7. Correct. Both pointer to member and pointer to method typically have
    a completely different meaning and representation to normal pointers,
    including a different bitpattern to represent the null pointer (the 0 value
    is already used for offset 0 or the first virtual function). Since there is
    a lot more complexity in C++, different C++ compilers all do something
    different (and binary incompatible) - except when adhering to a common
    ABI.

    C function pointers and data pointers are best not mixed.

    Wilco
     
    Wilco Dijkstra, Jan 31, 2008
    #7
  8. KKL

    David Brown Guest


    It's also important to note that function pointers are not directly
    compatible with data pointers - you can't necessarily convert a function
    pointer to a void* and back again, and expect a valid result (although
    it should work in practice, at least on 32-bit processors). You can't
    ever convert a method pointer to a function pointer (unless it's a
    static method).

    Personally, I think phrases such as "(void ()(void)* ) funcPtr" are
    ugly and hard to read. Use typedefs - they make your code clearer,
    minimise mistakes, and make it easier to change later:

    typedef void (*FVoid)(void);

    int taskCreate(char* taskName, FVoid funcPtr, ....)
     
    David Brown, Jan 31, 2008
    #8
  9. KKL

    KKL Guest

    Hi Habib,

    I am a new use to the group and did not know that putting code
    snippets that do not compile is such a serious offense even if you are
    discussing here some logical issues here and not syntactical ones.

    Ok, so I accept my offense that the code snippets have syntactical
    issues and that is because I did not simply copy it from my C source
    files but just wrote it in hurry to put up an example for my point of
    discussion which was "IS TYPE CASTING FUNCTION POINTERS FROM void (*)
    (int) TO (void *) AND BACK TO void (*)(void) AND THEN USING IT TO
    CALL FUNCTIONS IS A VALID AND SAFE OPERATION OR NOT".

    And regarding your comment about Good luck to those that work with me,
    may be you don't know that if making logical mistakes costs you much
    more than making syntactical mistakes and those mistakes are mostly
    done by people who stresses more on syntax rather than the actual
    thing which is LOGIC. So a good luck is required more to people who
    miss the whole point and and try hard to prove their knowledge
    stressing on the syntax (since that itself is hard thing for them).

    So, now I think you know what it means to take offense.

    Regards
     
    KKL, Jan 31, 2008
    #9
  10. KKL

    Arlet Ottens Guest

    According to the C99 standard, paragraph 6.3.2.3p8:

    "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."

    In other words, it is safe to convert them, as long as you convert them
    back to the original type before calling the function. If you call them
    as a different type, the behavior is undefined (potentially crashing
    your program)
     
    Arlet Ottens, Jan 31, 2008
    #10
  11. Le Thu, 31 Jan 2008 10:35:11 -0800, KKL a écrit:
    Is there a real difference between a clear mind and a clear syntax?
    The clear syntax reveals a clear thought.
    It is believed that the often obscure code is effective but most of
    the time it is not.
    I agrre with you, the logical errors are those that cost the most and
    therefore there is no need to add syntax errors.
    Best regards KKL,
     
    Habib Bouaziz-Viallet, Jan 31, 2008
    #11
  12. KKL

    Stef Guest

    In comp.arch.embedded,
    He posted C++ code IIRC, so that standard does not apply.
     
    Stef, Jan 31, 2008
    #12
  13. KKL

    KKL Guest

    Hi KKL !
    There is a huge huge difference between a clear mind and clear syntax.
    Any automation tool can generate clear syntax and any compiler can
    tell syntax mistakes and corrections, so do you conclude that tool
    have a better mind (the thought power ) to write programs.

    Look at my code the dots dots dots "............" , are all around,
    including the function defintions and calls. Why on earth would you
    think that the code was meant to compile. It was meant to discuss a
    point that I have already explained.

    So, I would sugest you to restrain from making such comments as "Good
    luck to those who work with you", A person who can see the roots (the
    underlying points) (with an actual clear mind) only has the right to
    make judgements.
    May be you are right here. The thoughtful people with clear mind would
    never let the compiler do their job of complaining about the
    syntax.Since if it does then it will prove that compiler has clearer
    mind than us and how is that possible.
     
    KKL, Feb 1, 2008
    #13
  14. Le Fri, 01 Feb 2008 06:23:13 -0800, KKL a écrit:
    You forgot i mention "no offense". Would you be so kind to agree my
    apologies.
    Best regards, Habib
     
    Habib Bouaziz-Viallet, Feb 1, 2008
    #14
  15. KKL

    KKL Guest


    Oops, I took it too seriously, as I was hurt.

    Regards & Apologies
    KKL
     
    KKL, Feb 1, 2008
    #15
  16. The first rule of casting is: don't.
    In particular for function pointers, if they don't compile, they won't
    run. If they only compile after casting, they won't run.

    If you have to ask the question, about how, instead of having studied
    the assembler code the compiler generates, you shouldn't use casting.
    Casting is a very rude remark to the compiler:
    "Shut up! *I* know better!"

    Your first priority is to get your code past the compiler, without
    casting. There is no guarantee that it will run then, but at least
    you stand a chance.

    Groetjes Albert.
     
    Albert van der Horst, Feb 11, 2008
    #16
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.