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

C Programming and pointer sizes on ARM processors.

Hi,

I've a question regarding C programming on ARM processors. can I ALWAYS assume that the sizeof(function_pointers) == sizeof(void *) == sizeof(char *)? Also I read in a blog (Caches and Self-Modifying Code) that "ARM architecture is often considered to be a Modified Harvard Architecture" does this mean the instructions are placed in a different memory space than the data memory space?  If so again how can we guarantee the sizeof (function_pointer) == sizeof(data_pointer)?

Thanks.

Parents
  • In case you need to reserve space for a 'pointer to something', which can be either data or a function, you could use 'union'

    union

    {

        void (*function)();

        void *data;

    };

    Thus you should of course make some way to distinguish whether the pointer is a function or data pointer.

Reply
  • In case you need to reserve space for a 'pointer to something', which can be either data or a function, you could use 'union'

    union

    {

        void (*function)();

        void *data;

    };

    Thus you should of course make some way to distinguish whether the pointer is a function or data pointer.

Children
  • Hi jensbauer,

    your description is based on the assumption that both pointer sizes are equal. It is denied by Peter. So I give recommendation of type cast.

    Best regards,
    Yasuhiko Koumoto.

  • Nope. I must disagree.

    My intention of the code snippet is to reserve enough space for both pointer types in for instance a structure.

    Thus the largest pointer size will be the dominating size.

    If one pointer is 32 bit and the other is 64 bit, then there will be room for a 64 bit pointer, but there's also room for the 32-bit pointer.

    A typecast would not work with structures, because then you would have to know in advance which pointer type is largest, and if your guess is wrong, you will overwrite other members of the structure (or write past the end of the structure).

    All that said, I rarely find that it is necessary to do these things anymore. I almost always find a cleaner way.

    If I can, I try avoiding typecasts, or resolve them.

    Sadly, with microcontrollers, it's very difficult to avoid it completely, because almost all hardware registers are defined as uint32_t, not pointers, although they are in fact pointers to memory areas (eg. DMA SrcAddr, DstAddr and LLI for instance). In such cases, we can only typecast and hope we're doing the right thing, because if something changes, we won't get a warning.

  • As for the latter part of your comments, I understand well and agree you. As for the former part, I cannot find significance. I think the understanding for the typecast is different from you. You seems to think it is a method of not causing warnings. I believe it is the only method of data conversion. I think we need not to care the pointer size. By the way, why do you mention the pointers in the structure?

  • There are parts of my reply that are not always valid, and parts of your reply, which also are valid in some cases. Why I mention the structure, is because it's likely that aps would store a pointer to something as a structure member or directly in memory.

    I've used structures to hold some data, which could be of different types myself.

    Personally, I avoid typecasting if possible.

    Here's my solution to a problem where I need to supply a pointer to memory, but I do not know what datatype it actually points to; it can be one of 3 types:

    typedef struct GDevice GDevice;

    struct GDevice

    {

       GDevice *next;

       union{

           void *address;

           uint32_t *address32;

           uint16_t *address16;

           uint8_t  *address8;

       };

    };

    Now the above is not critical code, and all pointers are of the same size. But I do not have to typecast at all. When I set the address, I write to 'address'. When I need the 32-bit pointer, I read address32. When I need the 16-bit pointer, I read address16.

    I can do this, because I know the memory location will always be divisible by 4.

    If I had to typecast, my code would look very messy (I actually cleaned up typecasting this way; it can make a huge difference in how your code look).

    Another advantage is that you do not have to go through every reference in case you one day need to change a uint16_t to a pixel16_t. You don't need to fix up all the type-casts. (Yes, in the particular code, I use pixel8_t, pixel16_t and pixel32_t now, plus a pixel_t of course).

  • Thank you for detailed explanations. I understand your style and it may be useful. I might sometimes use your coding style in the future.