I am just starting to learn C#, and I created 2 methods based on CRC16 C# implementations on Sanity Free website.
Can someone help me understand when and why to use these two different C# CRC16 implementations, using Right shift or Left shift? I think the second one has a mistake in it.
static ushort Crc16_SHL(byte[] bytes, ushort poly, ushort initialValue)
{
ushort[] table = new ushort[256];
ushort temp, a;
ushort crc = initialValue;
for (int i = 0; i < table.Length; ++i)
{
temp = 0;
a = (ushort)(i << 8);
for (int j = 0; j < 8; ++j)
{
if (((temp ^ a) & 0x8000) != 0)
temp = (ushort)((temp << 1) ^ poly);
else
temp <<= 1;
a <<= 1;
}
table[i] = temp;
}
for (int i = 0; i < bytes.Length; ++i)
{
crc = (ushort)((crc << 8) ^ table[((crc >> 8) ^ (0xff & bytes[i]))]);
}
return crc;
}
static ushort Crc16_SHR(byte[] bytes, ushort poly, ushort initialValue)
{
ushort[] table = new ushort[256];
ushort temp, a;
ushort crc = initialValue;
for (int i = 0; i < table.Length; ++i)
{
temp = 0;
a = (ushort)(i >> 8);
for (int j = 0; j < 8; ++j)
{
if (((temp ^ a) & 0x0001) != 0)
temp = (ushort)((temp >> 1) ^ poly);
else
temp >>= 1;
a >>= 1;
}
table[i] = temp;
}
for (int i = 0; i < bytes.Length; ++i)
{
crc = (ushort)((crc >> 8) ^ table[((crc >> 8) ^ (0xff & bytes[i]))]);
}
return crc;
}
If you are choosing your own CRC definition, where you are writing the code on both ends, it doesn't matter, other than a small speed benefit for the right shift.
It is more common however that you need to implement a CRC that has been defined as part of a protocol or format. Then part of that definition is whether the CRC is reflected or not. A reflected CRC uses right shifts, a non-reflected CRC uses left shifts.
You can see many such CRC definitions here. There you will see
refin=true refout=truefor reflected CRCs andrefin=false refout=falsefor non-reflected CRCs. The other parameters are the width in bits, the polynomial, the initial value, and the final exclusive-or.(You will find one weird CRC there with
refin=false refout=true. That one needs the resulting CRC reflected.)By the way, there are bugs in your
Crc16_SHR(). Youra = (ushort)(i >> 8);makesaalways zero! Get rid ofaand useif (((temp ^ i) & 0x0001) != 0). A little further down, the table indexing is messed up, where that line throws away the low eight bits ofcrcentirely! That needs to be:table[0xff & (crc ^ bytes[i])].Also I'd recommend moving the tables outside of the function and initializing them just once for a given polynomial. There's no point in doing the exact same calculations over and over again every time you call these functions. Especially if your messages are short, in which case generating the table every time makes it slower instead of faster.