LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Calculating checksum of a structure (https://www.linuxquestions.org/questions/programming-9/calculating-checksum-of-a-structure-275434/)

george_mercury 01-08-2005 01:19 PM

Calculating checksum of a structure
 
Hi! I need to know, how to calculate the checksum of this structure:
Code:

struct stepdata {
        uint8_t cmd;
        uint8_t acca;
        uint8_t accb;
        uint16_t indx;
        uint16_t indy;
        uint16_t stack;
        uint8_t status;
        uint32_t oppcode;
        uint8_t checksum;
};

I've tried to make a pointer in order to read the data of the structure byte-by-byte, but no matter what I do I get "incompatible pointer type". So what should I do?

George

Inunu 01-08-2005 08:55 PM

Hi George.

You can explicitly cast one pointer to another of different type by doing something like this and use the new pointer to process whatever that is in there.
char *ptr=(char *)&data;

Unfortunately in your example it will run into some problem because the stepdata structure is not well-aligned. GCC will pad bytes to make 32bit int's and struct boundary aligned to 32bit unless you ask it not to do so with __attribute__((packed)).

See http://www.delorie.com/djgpp/v2faq/faq22_11.html for more details about sizeof struct and extra paddings.

Code:

#include <stdio.h>
#include <stdint.h>

struct stepdata {
        uint8_t cmd;
        uint8_t acca;
        uint8_t accb;
        uint16_t indx;
        uint16_t indy;
        uint16_t stack;
        uint8_t status;
        uint32_t oppcode;
        uint8_t checksum;
} __attribute__((packed)); /* NOT TO PAD, otherwise sizeof(struct stepdata)=20 instead of 15 */

unsigned char checksum(char *data, int sz){
  int i;
  unsigned char checksum;
  for(i=0, checksum=0; i<sz; i++)
    checksum+=data[i];
  return checksum;
}

void dump(unsigned char *data, int sz){
  int i;
 
  printf("Dump data (%d):", sz);
  for(i=0; i<sz; i++){
    if((i&7)==0) printf("\n");
    printf("%02X ", data[i]);
  }
  printf("\n");


main(){
  struct stepdata data={1,2,3,4,5,6,7,8,0};
  unsigned char *ptr=(unsigned char *)&data;
  int sz=sizeof(struct stepdata);
 
  dump(ptr, sz);
  data.checksum=checksum(ptr, sz);
  printf("\nCalculated checksum: %2X\n", data.checksum);
  dump(ptr, sz);
}

Here is the result.

linux~$ ./checksum
Dump data (15):
01 02 03 04 00 05 00 06
00 07 08 00 00 00 00

Calculated checksum: 24
Dump data (15):
01 02 03 04 00 05 00 06
00 07 08 00 00 00 24

randyding 01-08-2005 10:15 PM

One more bit of info about your packing problem, if you choose to force byte packing of that structure you will get a "Bus Fault" if you compile and run your software on any processor other than Intel X86 because the 16 and 32 bit integers will not be word aligned. For example, it will crash on a Sparc.
i.e... struct stepdata data={1,2,3,4,5,6,7,8,0}; **bus fault**
But it will work on Intel.

Inunu 01-09-2005 05:07 AM

In x86 it can get away from crashes, but with performance penalty. To avoid this you should

1) manually pad extra bytes so that int16 words and int32 dwords are 16bit and 32bit aligned respectively, or
2) define dedicated function to perform the checksum over this particular structure type

The following one is an attempt to

A) align int16 and int32 variables., and
B) keep struct size multiple of 32bit.

(If you don't do B, once you have an array of this struct, the 2nd one may have everything mis-aligned.)

Code:

struct stepdata {
        uint8_t cmd; /* 00 */
        uint8_t acca; /* 01 */
        uint8_t accb; /* 02 */
        uint8_t pad1; /* 03 */

        uint16_t indx; /* 04 */
        uint16_t indy; /* 06 */

        uint16_t stack; /* 08 */
        uint8_t status; /* 0A */
        uint8_t pad2; /* 0B */

        uint32_t oppcode; /* 0C */

        uint8_t checksum; /* 10 */
        uint8_t pad3[3]; /*11 */
};



All times are GMT -5. The time now is 07:51 AM.