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

Change list for RealView Compilation Tools available?

The Release_Notes.htm file in the ARM compiler gives an overview of changes made between MDK-ARM versions, but is there somewhere I can find out exactly what bug fixes/improvements have been made to the RealView compiler itself?

The behaviour of the compiler has changed between MDK-ARM versions 4.03a and 4.10, which is not surprising since the compiler is a new version in this release. However, this has resulted in some code developed on 4.10 (which compiles with no warnings) to fail with an error during compilation on 4.03a. Specifically I have a function which accepts a pointer to void, and am passing a function pointer to it.

I can make the code compile on both versions with some casting, but I would like to be able to see if this issue is known and if there are other issues we should be wary of.

Parents Reply Children
  • Not really. There are some differences between MDK armcc and RVDS armcc. In particular you won't typically find the same build numbers, which renders the RVDS changelist rather useless for tracking MDK changes. But I don't have a better idea either...

    --
    Marcus
    http://www.doulos.com/arm/

  • Thank you, that is exactly the information I was after.

    And thank you Per for a clear, concise and non-judgemental explanation of the issue. Hopefully this thread will be useful for others as well.

    I think there is still a PC in our lab that hasn't been update with the latest compiler version, if so I will build again and make a note of the error code, but the error was about a non-compatible argument type, which certainly fits in with the references provided in this thread.

  • Yes, I see what you mean regarding version numbers. Not ideal, but I can at least search to see if a specific issue has been noted/fixed.

    If anyone is interested the actual error was:

    const void * LDR_TranslateAddress(const void *addr);
    
    uint8_t MyFunc( void );
    
    ((uint8_t (*)(void))LDR_TranslateAddress( MyFunc ))();
    
    error:  #167: argument of type "uint8_t (*)(void)" is incompatible with parameter of type "const void *"
    

    This clearly ties in to the C standard. Whilst the behaviour is undefined in the standard and the compiler is free to do what it wants, it seems quite reasonable for the compiler to permit this on the targets where it will work.

    I suppose a good follow on question is: "Is there a portable way to pass an arbitrary type of function pointer?"

  • Interesting. I was not aware of the fact that casting from function pointer to void pointer is not really allowed.

    A small question then:

    I use something similar and want to be able to cast all function pointers to one type. Since void* is not good, can I use:

    void (*) (void)

    ?

    The specifications says that I can:
    c0x.coding-guidelines.com/6.3.2.3.html (766 - "A pointer to a function of one type may be converted to a pointer to a function of another type and back again")

  • That is exactly the type of thing I have done in the past.

    Casting from a generic function pointer to a specific one as required.

    Hope someone more au fait with the specifications could comment.

  • I use something similar and want to be able to cast all function pointers to one type.

    That's allowed, but rather rarely a good idea.

    Quoting C99 6.3.2.6 paragraph 8 (emphasis mine):

    If a converted pointer is used to call a function whose type is not compatible with the pointed-to type,
    the behavior is undefined.
    

    I.e. you must cast back to the original type before you can use the pointer, which begs the question: what could possibly have been the point of casting it in the first place?

    You'll have to carry around information about the actual function type in some other way (an enum specifying one of several signatures, most likely), to know which function type to cast back to. But then you can just as well do away with the cast and keep the various types of function pointer in a union instead.

    Or better still, thoroughly re-investigate the line of decisions that led to the wish to cast function pointers in the first place.

  • I suppose a good follow on question is: "Is there a portable way to pass an arbitrary type of function pointer?"

    IMHO, no, there isn't, because passing a function pointer as any other type than its own throws away information that you cannot do without if you're ever going to use that function pointer (see my other post about the consequences of C99 6.3.2.6 p8).

    I.e. if you really want to pass a "generic function", it can't be just the pointer. You always need information about the type it originally had, too. And that information really had better be kept together with the pointer itself, in a struct. But then, once you've gone there, you no longer need function pointer casts:

    typedef void (*t_func_void_of_void)(void);
    typedef uint8_t (*t_func_uint8_t_of_void)(void);
    /*expand as needed */
    
    typedef struct generic_function_handle {
         enum {
            E_FUNC_VOID_OF_VOID,
            E_FUNC_UINT8_T_OF_VOID,
            /* expand as needed */
         } f_type;
         union {
            t_func_void_of_void func_void_of_void;
            t_func_uint8_t_of_void func_uint8_t_of_void;
            /* expand as needed*/
         } f_pointer;
    } generic_function_handle;
    

  • Thanks for the answer. I had seen the information in your quote, but probably should have mentioned that I do indeed always cast back.

    The way I use is it as follows.

    Basically, I need to initialize a table/database that contains functions to be called. For this purpose I had created a union that holds function pointers:

    typedef union {
            void    void*;
            void    (*main) (<arguments>);
            int8u   (*table)(<arguments>);
            int8u   (*text) (<arguments>);
    } layout_fptrs_u;
    

    I then have a struct for my table/database

    typedef struct
    {
            const int8s *name; // name of the element
            layout_fptrs_u func;
    } layout_elements_t;
    

    And the actual table itself:

    layout_elements_t g_main_elements_table[] =
    {
            { "Text",                     sys_process_text },
            { "Table",                    sys_process_table },
            { "Title",                    sys_process_title },
    };
    

    The table is initialized statically, so where at first i did not have the void* member in the union and the compiler complained because the function were not necessarily of the member named 'main'. (Initializing unions always initializes using the first member-type)

    So I added the void* as the first member, which worked. Now, I changed it to:

    typedef union {
            void    (*do_not_use)(void);
            void    (*main) (<arguments>);
            int8u   (*table)(<arguments>);
            int8u   (*text) (<arguments>);
    } layout_fptrs_u;
    
    typedef void (*void_fptr_t)(void);
    

    and the table:

    layout_elements_t g_main_elements_table[] =
    {
            // Standard Elements
            { "Text",                     (void_fptr_t)sys_process_text },
            { "Table",                    (void_fptr_t)sys_process_table },
            { "Title",                    (void_fptr_t)sys_process_title },
    };
    

    I could have casted the fptr of the 'main' member as well though.

    All I really use it for it to initialize my table. Nothing else uses the do_not_use member of the unio.

  • (Initializing unions always initializes using the first member-type)

    As of C99, not necessarily. Among the things they added on top of C90 were named designators and non-default union initialization. So instead of this:

    layout_elements_t g_main_elements_table[] =
    {
            // Standard Elements
            { "Text",                     (void_fptr_t)sys_process_text },
            { "Table",                    (void_fptr_t)sys_process_table },
            { "Title",                    (void_fptr_t)sys_process_title },
    };
    
    


    you could now do

    layout_elements_t g_main_elements_table[] =
    {
            // Standard Elements
            { "Text",                     {.text = sys_process_text} },
            { "Table",                    {.table = sys_process_table } },
            { "Title",                    {.text = sys_process_title } },
    };