Search code examples
cpointersstructuremicrocontrollerdereference

Why does casting a struct address to an int pointer, dereferencing, and using that as the LVALUE in a statement crash my microcontroller?


The following code crashes my microprocessor at runtime.

struct dummytype dummy;
struct crummytype crummy;
*(unsigned int*)&dummy = *(unsigned int*)&crummy;

Assuming both structs are the same size, is there something about this code that is not valid C? Is its validity contingent on anything particular?


Solution

  • This is only valid if both structures have an unsigned int as the first member.

    C99 §6.7.2.1/13

    Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

    Putting that simply, given an address of a structure object, you can cast that address to a pointer-to-first-member-type:

    struct A
    {
        unsigned int n;
        char junk[5];
    };
    
    struct A a;
    unsigned int *p = (unsigned int *)&a;  // OK. pointer is proper for first member type
    unsigned long*x = (unsigned long *)&a; // BAD
    

    In short, your code is only legitimate if both structure types have an unsigned int for their first member. Anything else is undefined behavior (void * not withstanding, but since it is non-dereferencable, it really isn't applicable here). Each structure type being "big enough" to hold an unsigned int isn't enough. Their first member must actually be an unsigned int.