It is not the fact that the structure contains different data types that is really the problem - you can cast the address of the object you need to checksum to a uint8*
and treat it as a byte array.
Your real problem is that the compiler is free to align the members in an implementation defined manner and insert padding between members to force that alignment. The value of the padding bytes is non-deterministic but the checksum will include them, making them non-comparable between instances.
The simple solution is to override the natural alignment and "pack" the structure by whatever means your compiler provides. This has merit for a severely resource constrained systems, but is not always appropriate. You you might instead consider a serialisation function where the members are copied individually to a byte array and you checksum that instead. However serialisation is resource and processor intensive compared to compiler packing and potentially error prone and a maintenance overhead.
An alternative to packing and serialisation might be to initialise the entire struct space for every such object with a memset()
, so that the padding will have a known zero value, but that is hard to maintain and enforce too if you have several such objects.
So let's say on balance you decide to pack this structure by whatever means (compilers variously support __attribute__ or
#pragma` or even a global compiler option. Then you might reconsider your structure design to split the header from the checksum and payload:
typedef struct
{
uint32 startAddress;
uint16 size;
uint32 EndAddress;
uint8 type;
uint8 version;
uint16 modelNo;
} __attribute__((__packed__)) sHeader ;
typedef struct
{
sHeader header ;
uint8 checksum;
uint8 reserved[32];
} __attribute__((__packed__)) sInfo ;
Then given:
sInfo some_info = ... ;
Then:
info.checksum = 0 ;
for( int i = 0; i < sizeof(some_info .header); i++ )
{
info.checksum += ((uint8*)(&some_info.header))[i] ;
}
If you choose to stick with your existing structure then it gets slightly more complicated:
typedef struct
{
uint32 startAddress;
uint16 size;
uint32 EndAddress;
uint8 type;
uint8 version;
uint16 modelNo;
uint8 checksum;
uint8 reserved[32];
} __attribute__((__packed__)) sInfo ;
sInfo some_info = ... ;
Then:
ptrdiff_t header_length = (uint8*)(&some_info.checksum) - (uint8*)(&some_info) ;
info.checksum = 0 ;
for( int i = 0; i < header_length; i++ )
{
info.checksum += ((uint8*)(&some_info.header))[i] ;
}
This second method as well as being more complicated an error prone, used a run-time calculate header size rather then the compile time sizeof()
of the first.