原始 C 代碼核心
u16 CRC_calc(u8 *pStr, u8 Len) {
u8 RsltHi = 0xFF, RsltLo = 0xFF, Index;
while (Len--) {
Index = RsltHi ^ *pStr++;
RsltHi = RsltLo ^ CRCHi[Index];
RsltLo = CRCLo[Index];
}
return (RsltLo << 8) | RsltHi; // 低位在前 (Little Endian)
}
Java 移植版 (含完整查表陣列)
public class CRC16 {
private static final byte[] CRCHi = { ... }; // 256 元素,同 C 陣列
private static final byte[] CRCLo = { ... };
public static int calc(byte[] data) {
int hi = 0xFF, lo = 0xFF;
for (byte b : data) {
int index = (hi ^ (b & 0xFF)) & 0xFF;
hi = (lo ^ (CRCHi[index] & 0xFF)) & 0xFF;
lo = CRCLo[index] & 0xFF;
}
return ((lo << 8) | hi) & 0xFFFF; // 返回 unsigned short
}
}
關鍵移植細節
- 無符號位元運算:Java 無 unsigned,所有中間值
& 0xFF 保證 8 位;最終結果 & 0xFFFF 保證 16 位。
- 位元組序:原 C 代碼
(RsltLo<<8)|RsltHi 為 **Little Endian** (低位元組在前),Java 維持相同序;若上層協定為 Big Endian,需交換 hi/lo。
- 查表陣列:必須與 C 版完全一致 (CRC-16/IBM, CRC-16/Modbus 等不同多項式陣列不同),建議單獨測試已知向量驗證。
測試向量
// CRC-16/Modbus 範例
byte[] test = "123456789".getBytes(StandardCharsets.US_ASCII);
assert CRC16.calc(test) == 0x4B37; // 標準結果