-1

I need to fill the binary with this header. Checksum of the header will be add end of the header.checksum should be 1 byte sum

typedef struct {
    uint32 startAddress;
    uint16 size;
    uint32 EndAddress;
    uint8 type;
    uint8 version;
    uint16 modelNo;
    uint8 checksum;
    uint8 reserved[32];
}
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
Vamsi Chowdary
  • 49
  • 1
  • 1
  • 2
  • For example I have typedef struct { uint32 startAddress; uint16 size; uint32 EndAdenter code heredress; uint8 type; uint8 version; uint16 modelNo; uint8 checksum; uint8 reserved[32]; }HedareInfo; – Vamsi Chowdary May 15 '20 at 18:25
  • There will be unitialized gaps. `size` is 16 bits, so `EndAddress` will align to an offset of 8 [because it aligns to a 32 bit (4 byte) boundary. Thus, there will be two bytes _between_ `size` and `EndAddress` that will be unaccounted for. So, you'll probably have to checksum each struct field individually. You might consider adding `__attribute__((__packed__))` to prevent such alignment. Or, you could add `uint8 pad[2]` between `size` and `EndAddress` and force it to a known value (e.g. 0) – Craig Estey May 15 '20 at 18:33
  • @CraigEstey I'd recommend against that. `__attribute__((packed))` should be banned, and manually adding padding is a bad idea, not only because it's fragile (depending on the implementation-deoendent size/alignment of other fields), but also fragile depending on how the struct is written to. Use a sane serialization technique instead. – EOF May 15 '20 at 18:54
  • The structure is a data type, not a data object - you cannot generated a checksum of a data _type_. – Clifford May 15 '20 at 19:24
  • @EOF packed is useful when dealing with H/W I/O ports in kernel, RTOS, or standalone R/T. I tend not to use it, but, when dealing with small R/T systems, it's sometimes the only way to get the code to fit in the ROM. – Craig Estey May 15 '20 at 19:35
  • @EOF packed is also useful for: `typedef struct { unsigned char rgbtRed; unsigned char rgbtGreen; unsigned char rgbtBlue; } __attribute__((__packed__)) RGBTRIPLE;` – Craig Estey May 15 '20 at 19:39
  • Also the typedef is incomplete. – Clifford May 15 '20 at 19:40
  • @CraigEstey If your hardware requires packed structs to access it, it was probably designed in the 80's. Your `RGBTRIPLE` has trivial alignment requirements (`1`), so packing it does nothing. – EOF May 15 '20 at 22:03
  • @EOF Hmm ... It's not _my_ `RGBTRIPLE`. It's part of `cs50`, and more importantly, part of `bmp.h` and they use packed. So, compatibility ... – Craig Estey May 16 '20 at 01:11
  • @EOF As to H/W "designed in the 80's", I've seen _new_ code, designed "last week" that does something like `char, char, int` that _must_ be packed. Done by a H/W guy, for custom logic in an FPGA who fancies themselves to be a programmer after they've written a 50 line embedded loop. The code and _logic_ has already shipped. And, because the H/W guy owns the company, one is not allowed to refactor and/or serialize it (e.g. as a "cost" decision, you don't get paid to redo it, so you have to live with it). `x =- 5` is deprecated for 3+ decades (vs. `x -= 5`) but C still has to support it. – Craig Estey May 16 '20 at 01:27
  • @CraigEstey If the hardware designer *wants* their hardware to be obsolete the moment it is made, why not? Well, aside from the question *how* any bus used to access the relevant hardware registers would guarantee the atomicity of an access like that, which I don't believe any bus will do. Either way, what does setting `x = -5` have to do with anything? Why would that be unsupported? Unless you expect `x =- 5` to result in `x -= 5`, which it *absolutely does not, on any sane compiler respecting any c standard*. – EOF May 16 '20 at 05:41

1 Answers1

1

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.

Clifford
  • 88,407
  • 13
  • 85
  • 165