[net.lang.c] final solution to my typecasting problem

betz@decvax.UUCP (06/21/83)

Many thanks to all who responded to my query about typecasting
characters in C.

Here is the CRC routine that I ended up with after various
suggestions about how to get around the problem with unsigned
characters.  It seemed like the only real solution that was
compatible with most compilers was to avoid using the type
'unsigned char' and instead 'and' the possibly signed character
with 0xFF.  This generates bad code on some machines, but it
seems reasonable to recode a CRC routine in assembler for each
machine anyway in order to gain efficiency.  This routine will
work in the interim until an assembler routine can be written.

This is not the same algorithm that is used by the famous
CP/M MODEM program.  As far as I can tell, that program doesn't
compute CRCs correctly, but I may be wrong.  Anybody know if there
are multiple ways to compute CRCs?

This routine shifts new bits into the CRC from the left whereas
the routine used in MODEM shifts them in from the right.  This
routine xors the CRC with the polynomial whenever the xor of the
data bit and the bit shifted out of the right end of the CRC is one,
the MODEM CRC routine xors the CRC with the polynomial whenever the
bit shifted out of the left of the CRC is one.

Well, this is getting a little verbose, so I guess I'll just end
here.  Probably some of you out there are groaning and muttering
to yourselves about how completely uninformed about CRCs I must be
to have posed all of these questions.  You are right!

Thanks for everyone's help,

	David Betz
	decvax!betz

P.S.  I am aware that this routine only implements CRC correctly
for eight bit data bytes.

=================

/* crc - compute the CRC for an array of 8 bit bytes */

/*
	This routine calculates CRCs using the same
	algorithm as the VAX-11/780 CRC instruction.
 */

/* the CRC polynomial */
#define POLY	0x8408		/* use X^16 + X^12 + X^5 + 1 */

/* crc - compute the CRC for an array of 8 bit bytes */
int crc(buf,len)
  char *buf; int len;
{
    register char *bp;
    register unsigned int csum;
    register int j,i;

    /* initialize the buffer pointer */
    bp = buf;

    /* initialize the CRC */
    csum = 0xFFFF;

    /* compute the CRC */
    for (i = len; i--; ) {
	csum ^= *bp++ & 0xFF;
	for (j = 8; j--; ) {
	    if (csum & 1) {
		csum >>= 1;
		csum ^= POLY;
	    }
	    else
		csum >>= 1;
	}
    }

    return (~csum & 0xFFFF);
}