DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Compute A 16-bit Sum With Carry

04.29.2012
| 3465 views |
  • submit to reddit
        
/**************************************************************************/
/*                     compute a 16-bit sum with carry                    */
/*   nice feature of sum with carry is that it is byte order independent  */
/*       carry from hi-bit of one byte goes into lo-bit of other byte     */
/*   NOTE: assumes data in buf is in net format                           */
/**************************************************************************/

u_short
xsum(buf,len)
char     *buf;
int      len;
{
   register u_short   *sp;
   register int       slen;
   register u_long    sum;        /* >= 32-bit space to keep sum */
   union { u_short s; u_char c[2]; } xun;
   int                unaligned;

   sum = 0;

   unaligned = ((unsigned long)buf) & 0x1;
   /* If buffer isn't short aligned, need to get fisst byte */
   if (unaligned != 0) {
      xun.s = 0;
      xun.c[1] = buf[0];
      sum = xun.s;
      buf++; len--;
   } 
   slen = len/2;            /* length in shorts */

   /* LINT NOTE: next line has possible ptr alignment message, even 
      though we've made sure that buf is aligned */
   for(sp = (u_short *)buf; slen > 0; slen--,sp++) {
      sum += *sp;
   }

   /* is there a trailing odd byte? */
   if ((len & 0x1) != 0) { 
#ifdef DEBUG
      printf("xsum extra: 0x%X (sum: 0x%X, len %d.)\n", buf[len-1], sum, len); 
#endif
      xun.s = 0; xun.c[0] = buf[len - 1];
      sum += xun.s; 
   }

   /* Fold in all the carries to get a single 16 bit value */
   sum = (sum & 0xFFFF) + (((unsigned long)(sum & 0xFFFF0000))>>16);
   if (sum > 0xFFFF) 
   { sum = (sum & 0xFFFF) + 1; }

   if (unaligned != 0)          /* byteswap */
   { sum = ((sum & 0xFF)<<8) + ((sum & 0xFF00)>>8); }
   return (sum);
}