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

wrong evaluation of the compiler??... Very rare error

Dear all,

I have this ultra simple strcture

typedef struct
{ uint8_t Hora; uint16_t Data1;
} EEpromPaqueteDatosS;

When I do sizeof(EEpromPaqueteDatosS) it returns 4!!! But if I do the sizeof of the same structure with only one variable, in other words, with uint8_t variable it returns 1 and with uint16_t it returns 2.. but if the structure have the two variables it returns 4!!

Also if I copy the structure to a uint8_t vector I can found a strange byte in the middle.. like this:

EEpromPaqueteDatosS EEpromPaqueteDatos;
uint8 data[4];

EEpromPaqueteDatos.Hora = 0x10;
EEpromPaqueteDatos.Data1= 0x1020;

When I copy the structure to data, data is like 0x10, 0x??, 0x20, 0x10.. why this extra byte!!!!

Can anybody help me with this???

Thanks

Parents
  • > if you decide to pack your structures they will take less memory
    > (who cares) but have a speed penalty (you should care).

    It depends. Many smartcards, intelligent sensors, etc. are using ARM
    processors these days and offer only some hundred byte of RAM, while
    the processing performance leaves enough headroom to justify less
    efficient memory access.

    > If you have a structure that start with a char, the packings
    > inserted may vary based on where ste struct end up being linked.

    I'd be surprised, since the location of struct members must be known
    at compile time.

    Kind regards,
    Marcus
    http://www.doulos.com/arm/

Reply
  • > if you decide to pack your structures they will take less memory
    > (who cares) but have a speed penalty (you should care).

    It depends. Many smartcards, intelligent sensors, etc. are using ARM
    processors these days and offer only some hundred byte of RAM, while
    the processing performance leaves enough headroom to justify less
    efficient memory access.

    > If you have a structure that start with a char, the packings
    > inserted may vary based on where ste struct end up being linked.

    I'd be surprised, since the location of struct members must be known
    at compile time.

    Kind regards,
    Marcus
    http://www.doulos.com/arm/

Children
  • Some programs are code-space limited.
    Some are RAM-space limited.

    Most of the time, people don't reach any of the limits.

    Sometimes, the packed data get you into extra troubles because multiple memory accesses means a read of the value can't be performed atomically.

    So it isn't something to do unless there is a very good motive for it.

  • My post included:
    "sure, the above, as all generalization, will have exceptions."

    Which should have covered It depends

    this
    >
    > If you have a structure that start with a char, the packings
    > inserted may vary based on where ste struct end up being linked.

    I'd be surprised, since the location of struct members must be known
    at compile time.

    example
    struct
    U8 x
    U16 y

    if the linker happen to be at an odd address when it link the struct no packing will happen, if it is at an even address there will be a packbyte inserted between the two.

    I solved the problem this way
    struct
    U32 dummy
    U8 x
    U16 y

    Sometimes, the packed data get you into extra troubles because multiple memory accesses means a read of the value can't be performed atomically.
    I could see some processors burp on this. I do not know if any ARMs would, but a good argument for not packing

    Erik

  • Basically, processors who can read "odd-aligned" data can do it because they have an intelligent memory controller that puts the processor core to sleep while the memory controller performs multiple memory accesses and then merges the relevant bytes.

    The memory controllers inside Intel x86 chips have a tradition of silently hiding odd aligns. So x86 programs have by tradition always managed, while same source code recompiled on Sun or other platforms have resulted in "bus error" exceptions when the memory controller have received an unsupported request.

    For processors with this feature in the memory controller interface, you have compiler options to specify align just for performance. Even if the memory interface is pipelined, you still increase the probability of a pipeline stall when the memory controller must perform two sequential accesses.

    For processors where the memory controller can not perform this merge, the compiler really must insert code for multiple reads/writes. A 4-byte integer one byte off can requires a read/modify/write to fix that odd byte and a read/modify/write to fix the other three bytes. Few processors have a lock primitive where the processor can lock the bus (dma or possibly external memory accesses by other devices) and/or lock interrupts from interfere with these two read/modify/write actions.

    About structs and linking - a "normal" compiler/linker, i.e. a compiler/linker that are following the C language standard, would not do any three-byte optimization of a struct just because the linker has the option to place the struct at an odd or even location. If the struct has an alignment critieria larger than 1, then the compiler has to make the struct n times that alignment criteria. And make the relevant fields inside the struct placed so they fulfill that requirement. And the linker must place the full struct so the struct is aligned to this - or better - alignment level.

    So there isn't a difference between:

    struct {
        uint8_t a;
        uint16_t b;
    } alt_1;
    
    struct {
        uint16_t a;
        uint8_t b;
    } alt_2;
    

    If processor needs to have uint16_t aligned to even address, then alt_1 must be n*2 bytes large with field b at an even offset inside the struct. And alt_2 must be n*2 bytes large with a at an even offset inside the struct.

    So sizeof(alt_1) and sizeof(alt_2) will both be n*2 bytes large. And a memcpy(&alt_1,...) or memcpy(&alt_2,...) will be able to perform a memory copy without reacing any byte outside of the struct.

    And it will be possible to create arrays of above types and ever element in that array will start at a n*2 byte address since each element will be n*2 bytes large.

    Note that the C51 compiler don't need to worry about align from a processor perspective since the 8051 performs 8-bit memory accesses. So it's ok for the compiler to use zero padding and make above structures 3 bytes large. And the linker will be free to place variables of these types at odd or even addresses without needing to worry.

    The memory controllers in most ARM chips will not like the above as 3 byte structures, so the compiler will either add a pad or add a number of extra instructions to make only aligned accesses.

  • If the linker happen to be at an odd address when it link the struct no packing will happen, if it is at an even address there will be a packbyte inserted between the two.

    No, it won't. It's forbidden by the language definition.

    A given struct will always have the exact same layout, no matter where it ends up: on the stack, on the heap, or in statically allocated memory --- of which the latter is the only one the linker is really even involved with in any way.

  • If the linker happen to be at an odd address when it link the struct no packing will happen, if it is at an even address there will be a packbyte inserted between the two.

    No, it won't. It's forbidden by the language definition.

    well, if so Keil (recent version) breaks the "language definition"

    I caught this as a bug, and fixed it instead oof complaining to Keil.

    I do not know the "language definition" but the case in point was a const struct for the defaults and a struct for the initialized values. copying the defaults into the variable struct blew the thing.

    Erik

  • "I do not know the "language definition" but the case in point was a const struct for the defaults and a struct for the initialized values. copying the defaults into the variable struct blew the thing."

    Post the code sequence, and we may be able to come up with a reason for the problem.

  • if so Keil (recent version) breaks the "language definition"

    I'm with Per on that one: it'll take actual evidence to convince me of that. In a new thread, preferrably.

    I do not know the "language definition"

    And you say that (here and elsewhere) as if you're proud of it. I think you rather should be ashamed of it.