This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Problems with init of a function pointer

Hello

I've a problem when initializing a global function pointer. Depending on where the function pointer is created, the adress of the funciton pointer is 0 (=wrong). There are no warnings in the compiler!
Compiler: c166 v4.23
Tool: uVision2 v2.31

Example:

typedef UINT16 (*pModul_Para)(UINT16, UINT16 *, void *, UINT16);

//prototype of the function
UINT16 Controller_Para(UINT16 ParamNr, UINT16 *pElementNr, void *pValue, UINT16 Action);

//create and init the function pointer
pModul_Para FunctionPtr123 = &Controller_Para;

//Function definition
UINT16 Controller_Para(UINT16 ParamNr, UINT16 *pElementNr, void *pValue, UINT16 Action)
{ ...
}

//create and init a second function pointer
pModul_Para FunctionPtr55 = &Controller_Para;

--> Result: FunctionPtr123 would be 0, FunctionPtr55 can be the address of Controller_Para.

Any idea? Thanks!

Parents
  • It's not that it's not possible - but you didn't provide any evidence that you'd actually done it correctly in your code.

    I've noticed that in my original code are two equal prototype of the function (1 time in the header file, 1 time in the C file above). This should have no influence on the function of the program!

    I've created a new c.-File with two function prototypes.
    Result:
    pFunktionPointer_1 = 0 (wrong !!!???)
    pModul_Parameter pFunktionPointer_2 = 292384 (correct !!!)
    pModul_Parameter pFunktionPointer_3 = 292384 (correct !!!)

    #include <stdio.h>
    
    //Typedef of the function pointer
    typedef unsigned int (*pModul_Parameter)(unsigned int, unsigned int *, void *, unsigned int);
    
    //prototype of the function below
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action);
    
    //create and init the function pointer 1
    pModul_Parameter pFunktionPointer_1 = &CallThisFunction;
    
    //prototype of the function below
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action);
    
    //create and init the function pointer 2
    pModul_Parameter pFunktionPointer_2 = &CallThisFunction;
    
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action)
    {
      //Do anything
      static int q = 88;
      return ++q;
    }
    
    //create and init the function pointer 3
    pModul_Parameter pFunktionPointer_3 = &CallThisFunction;
    

Reply
  • It's not that it's not possible - but you didn't provide any evidence that you'd actually done it correctly in your code.

    I've noticed that in my original code are two equal prototype of the function (1 time in the header file, 1 time in the C file above). This should have no influence on the function of the program!

    I've created a new c.-File with two function prototypes.
    Result:
    pFunktionPointer_1 = 0 (wrong !!!???)
    pModul_Parameter pFunktionPointer_2 = 292384 (correct !!!)
    pModul_Parameter pFunktionPointer_3 = 292384 (correct !!!)

    #include <stdio.h>
    
    //Typedef of the function pointer
    typedef unsigned int (*pModul_Parameter)(unsigned int, unsigned int *, void *, unsigned int);
    
    //prototype of the function below
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action);
    
    //create and init the function pointer 1
    pModul_Parameter pFunktionPointer_1 = &CallThisFunction;
    
    //prototype of the function below
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action);
    
    //create and init the function pointer 2
    pModul_Parameter pFunktionPointer_2 = &CallThisFunction;
    
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action)
    {
      //Do anything
      static int q = 88;
      return ++q;
    }
    
    //create and init the function pointer 3
    pModul_Parameter pFunktionPointer_3 = &CallThisFunction;
    

Children
  • Hi r k,

    How do you get the values of pFunktionPointer_1, pFunktionPointer_2, pFunktionPointer_3?

    On the X86 platform, I can simply do this:

    int main(void)
    {
            printf("pFunktionPointer_1 = %d\n", pFunktionPointer_1);
            printf("pFunktionPointer_2 = %d\n", pFunktionPointer_2);
            printf("pFunktionPointer_3 = %d\n", pFunktionPointer_3);
            system("PAUSE");
            return 0;
    }
    

    But on the C166 platform, How do you get the values?

  • ran on C51 and ptr_1/2/3 point to the same thing.

    not sure about C166.

  • not sure about C166. but on C51, you just step through the code and watch the pointers.

  • Most compilers have a %p for printing pointers - potentially with a size flag to specify what type of pointer to print.

  • Hi Per,

    Many thanks for the %p information.

    I regularly find out that, I am not a competent C programmer. :>

    I also did some quick search, %p is for "Print a void * (pointer to void) in an implementation-defined format."

    as you mentioned in other thread, (Harvard architecture) data pointers and function pointers could be different in size. So I think the usage of %p would be quite complex to me.

    And actually, the variable number of arguments of printf() is something that I have never understood.

  • Hello

    I don't use printf or like this. I can see the adress of the pointer in the list file (.m66). So I read the contents of the address via an RS232 communication.

    Thank you for the efforts!

  • In fact, different types of data pointers could be different in size!

    eg, in C51, an XDATA pointer is larger than an IDATA pointer.

    Some implementations provide "near" and "far" pointers

    "the variable number of arguments of printf() is something that I have never understood"

    That is a standard part of the 'C' programming language - not specific to Keil.
    Therefore, and general 'C' reference material should be relevant...

  • Hi R K,

    Could you please explain more about how do you "read the contents of the address via an RS232 communication."?

  • Could you please explain more about how do you "read the contents of the address via an RS232 communication."?

    I have a self-made tool (on PC) which read the list file (.m66). This file contains the addresses of all the variables. I select with my self-made tool a variable (or a pointer) -> the tool send a RS-232 string with the adress to the microcontroller. So my C166 program on the microcontroller read with the keil function HVAR() (HVAR = read from a absolute memory address) the value of the variable and send a string with the variable content back to my computer.

  • I have a self-made tool (on PC) ...

    Sounds like a self-made rudimentary in-circuit debugger. A full-featured debugger would be more convenient.
    Anyway, the ultimate test would be to actually use the contents of the variable in your program. Like in a call to printf(). It could still be compiler optimization at work. Although I don't remember seeing any wonders of optimization from the C166 compiler.

  • Anyway, the ultimate test would be to actually use the contents of the variable in your program. Like in a call to printf(). It could still be compiler optimization at work.

    When I try to call the function with the "wrong" pFunktionPointer_1 then the program will crash. So I only read the function pointer (without calling it) with function Test()
    Result:
    pFunktionPointer_12 = 0 (wrong !!!)
    pFunktionPointer_22 = correct
    pFunktionPointer_32 = correct

    #include <STDLIB.H>
    
    //Typedef of the function pointer
    typedef unsigned int (*pModul_Parameter)(unsigned int, unsigned int *, void *, unsigned int);
    
    //prototype of the function below
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action);
    
    //create and init the function pointer 1
    pModul_Parameter pFunktionPointer_1 = &CallThisFunction;
    
    //prototype of the function below
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action);
    
    //create and init the function pointer 2
    pModul_Parameter pFunktionPointer_2 = &CallThisFunction;
    
    unsigned int CallThisFunction(unsigned int ParamNr, unsigned int *pElementNr, void *pValue, unsigned int Action)
    {
      //Do anything
      static int q = 88;
      return ++q;
    }
    
    //create and init the function pointer 3
    pModul_Parameter pFunktionPointer_3 = &CallThisFunction;
    
    
    
    void Test(void)
    {
      static pModul_Parameter pFunktionPointer_12, pFunktionPointer_22, pFunktionPointer_32;
    
     pFunktionPointer_12 = pFunktionPointer_1;
     pFunktionPointer_22 = pFunktionPointer_2;
     pFunktionPointer_32 = pFunktionPointer_3;
    
    }
    

  • John Linq,

    Could you post a link to that thread? I'd like to read it.
    Thanks.

  • So I only read the function pointer (without calling it) with function Test()

    That's insufficient. Your program must produce observable "side effects" that depend on the value of the variable, according to the C standard.

    When I try to call the function with the "wrong" pFunktionPointer_1 then the program will crash.

    That would probably qualify as a real "side effect". Although we didn't see the actual code.

    As I said before, this is probably a compiler and/or linker bug.

  • I forgot to mention that compiler/linker bugs should be reported to Keil. You can wait for a fix from them (requires a support contract, I think.)
    In the meantime, you can use some kind of a workaround. I think you found one: extra function prototypes and variables isolate the bug to a controllable area.

  • Hi Tamir,

    Tried quite a while to find that thread, but no luck; will re-try with other keywords later.