Skip to content

Instantly share code, notes, and snippets.

@edwardtoday
Last active December 29, 2016 08:53
Show Gist options
  • Save edwardtoday/7bf3ed0dab16fdf86e13e84f8db7badd to your computer and use it in GitHub Desktop.
Save edwardtoday/7bf3ed0dab16fdf86e13e84f8db7badd to your computer and use it in GitHub Desktop.
CRC16 CCITT / 16位CRC检验算法的C语言实现
CRC16 CCITT / 16位CRC检验算法的C语言实现
#include "crc16_sansi.h"
uint16_t gen_crc16_ref(const uint8_t *buffer, long buffer_length) {
unsigned char c = 0;
unsigned char treat = 0;
unsigned char bcrc = 0;
uint16_t wcrc = 0;
for (int i = 0; i < buffer_length; i++) {
c = buffer[i];
for (int j = 0; j < 8; j++) {
treat = c & 0x80;
c <<= 1;
bcrc = (wcrc >> 8) & 0x80;
wcrc <<= 1;
if (treat != bcrc)
wcrc ^= 0x1021;
}
}
return wcrc;
}
// https://github.com/antirez/redis/blob/3.2.6/src/crc16.c
/*
* Copyright 2001-2010 Georges Menie (www.menie.org)
* Copyright 2010-2012 Salvatore Sanfilippo (adapted to Redis coding style)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University of California, Berkeley nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* CRC16 implementation according to CCITT standards.
*
* Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
* following parameters:
*
* Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
* Width : 16 bit
* Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1)
* Initialization : 0000
* Reflect Input byte : False
* Reflect Output CRC : False
* Xor constant to output CRC : 0000
* Output for "123456789" : 31C3
*/
static const uint16_t crc16tab[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108,
0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b,
0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee,
0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d,
0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5,
0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4,
0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13,
0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e,
0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1,
0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0,
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657,
0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882,
0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e,
0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d,
0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
uint16_t gen_crc16_redis(const uint8_t *buffer, long buffer_length) {
int counter;
uint16_t crc = 0;
for (counter = 0; counter < buffer_length; counter++)
crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ *buffer++) & 0x00FF];
return crc;
}
#ifndef CRC16_SANSI_H
#define CRC16_SANSI_H
#include <stdint.h>
// At Sansi, we use CRC-16-CCITT for 2-byte checksums.
// Here are some implementations that have identical outputs.
// Found in previous protocol documentation.
// Readable but slow. Use this as a reference.
uint16_t gen_crc16_ref(const uint8_t *buffer, long buffer_length);
// Implementation used in Redis. Much faster than reference.
uint16_t gen_crc16_redis(const uint8_t *buffer, long buffer_length);
#endif /* CRC16_SANSI_H */
//
// main.c
// crc16
//
// Created by qingpei on 29/12/2016.
// Copyright © 2016 sansi. All rights reserved.
//
#include "crc16_sansi.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, const char *argv[]) {
if (argc < 2) {
printf("Usage: crc16 filename");
} else {
FILE *fp;
long lSize;
unsigned char *buffer;
fp = fopen(argv[1], "rb");
if (!fp)
perror(argv[1]), exit(1);
fseek(fp, 0L, SEEK_END);
lSize = ftell(fp);
rewind(fp);
/* allocate memory for entire content */
buffer = calloc(1, lSize + 1);
if (!buffer)
fclose(fp), fputs("memory alloc fails", stderr), exit(1);
/* copy the file into the buffer */
if (1 != fread(buffer, lSize, 1, fp))
fclose(fp), free(buffer), fputs("entire read fails", stderr), exit(1);
/* do your work here, buffer is a string contains the whole text */
clock_t start, diff;
uint16_t crc16 = 0;
unsigned long msec = 0;
start = clock();
crc16 = gen_crc16_redis(buffer, lSize);
diff = clock() - start;
msec = diff * 1000 / CLOCKS_PER_SEC;
printf("%-*s:\t", 20, "gen_crc16_redis");
printf("crc16=%hx\t", crc16);
printf("time=%ld.%03lds\n", msec / 1000, msec % 1000);
start = clock();
crc16 = gen_crc16_ref(buffer, lSize);
diff = clock() - start;
msec = diff * 1000 / CLOCKS_PER_SEC;
printf("%-*s:\t", 20, "gen_crc16_ref");
printf("crc16=%hx\t", crc16);
printf("time=%ld.%03lds\n", msec / 1000, msec % 1000);
fclose(fp);
free(buffer);
}
return 0;
}
CC=gcc
CFLAGS=-I. -g -Wall -O3
DEPS = crc16_sansi.h
OBJ = crc16_sansi.o main.o
TARGET = crc16
TESTFILE = testfile
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
$(TARGET): $(OBJ)
gcc -o $@ $^ $(CFLAGS)
clean:
rm -f *.o *~ $(TARGET) $(TESTFILE)
test:
# Creating a 100 MB test file with random content
dd if=/dev/random of=$(TESTFILE) bs=1000000 count=100 &> /dev/null
# generate crc16 for the test file
$(TARGET) $(TESTFILE)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment