Giter Site home page Giter Site logo

crcpp's Introduction

CRC++

Easy to use and fast C++ CRC library.

Tired of writing CRC code over and over again? Don't want to include a dozen boost header files just for a little bit of functionality? CRC++ is a portable and extremely lightweight alternative that is incredibly simple, fast, and clean.

Features

CRC++ supports bit-by-bit and byte-by-byte calculation of full and multipart CRCs. The algorithms used are highly optimized and can even be configured to be branchless (as always, be sure to profile your code to choose the most efficient option). CRC++ is a great option for embedded C++ projects with a need for efficiency.

CRC++ consists of a single header file which can be included in any existing C++ application. No libraries, no boost, no mess, no fuss.

Any CRC width is supported - even CRCs larger than 64 bits, provided there is an integer type large enough to contain it. Trying to compute a 57-bit CRC? Got you covered.

Many common CRCs are provided out-of-the-box, such as CRC-32 (used in PKZip and Ethernet), CRC-XMODEM, and CRC-CCITT.

CRC++ will compile with any reasonably compliant C++03 or C++11 compiler. Compiling with C++11 is recommended, as it allows a number of static computations to be performed at compile-time instead of runtime.

All of the CRC++ code is well-documented. Unit tests are included in the repository (g++ Makefile and Visual Studio 2015 projects included). HTML documentation can also be produced via Doxygen (also included in the repository).

Comparison

CRC++ boasts one of the fastest and most memory efficient generic CRC implementation available. The below table shows performance comparisons across multiple implementations and platforms.

Library Speed, x64 platform (100 million iterations) Speed, x86 platform (100 million iterations)
CRC++ 2050 milliseconds 2200 milliseconds
boost 2250 milliseconds 2000 milliseconds
pycrc 2050 milliseconds 2240 milliseconds
mhash 2250 milliseconds 2400 milliseconds

Additionally, CRC++ has the most features of any library and the smallest code footprint:

Library Number of include files Header-only implemen-tation Supports byte != 8 bits Supports arbitrary CRC width Custom type support C++11 support 40+ built-in CRC definitions Branchless implemen-tation
CRC++ 1 Yes Yes Yes Yes Yes Yes Yes
boost 17 Yes Yes Yes Yes Yes No No
pycrc 2 per CRC algorithm No No No No No No No
mhash 6 No Yes No No No No No

Usage

Computing a CRC is as simple as the following code:

#include "CRC.h" // Only need to include this header file!
                 // No libraries need to be included. No project settings need to be messed with.
				 
#include <iomanip>  // Includes ::std::hex
#include <iostream> // Includes ::std::cout
#include <cstdint>  // Includes ::std::uint32_t

int main(int argc, char ** argv)
{
	const char myString[] = { 'H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D' };
	
	std::uint32_t crc = CRC::Calculate(myString, sizeof(myString), CRC::CRC_32());
	
	std::cout << std::hex << crc;
	
	return 0;
}

Multi-part CRCs are also supported:

int main(int argc, char ** argv)
{
	const char myHelloString[] = { 'H', 'E', 'L', 'L', 'O', ' ' };
	const char myWorldString[] = { 'W', 'O', 'R', 'L', 'D' };
	
	std::uint32_t crc;
	
	crc = CRC::Calculate(myHelloString, sizeof(myHelloString), CRC::CRC_32());
	crc = CRC::Calculate(myWorldString, sizeof(myWorldString), CRC::CRC_32(), crc);
	
	std::cout << std::hex << crc;
	
	return 0;
}

This will return the same CRC as the first example.

If you need to compute a CRC on an input that is not a multiple of CHAR_BIT (usually 8 bits), use the CalculateBits() function instead:

int main(int argc, char ** argv)
{
	const unsigned char data[] = { 0x98, 0x76, 0x54, 0x32, 0x10 };
	
	// Second argument is the number of bits. The input data must
	// be a whole number of bytes. Pad any used bits with zeros.
	std::uint32_t crc = CRC::CalculateBits(data, 37, CRC::CRC_32());
	
	std::cout << std::hex << crc;
	
	return 0;
}

The above examples compute a CRC bit-by-bit. However, CRC++ also supports lookup tables, as the following example demonstrates:

int main(int argc, char ** argv)
{
	const char myHelloString[] = { 'H', 'E', 'L', 'L', 'O', ' ' };
	const char myWorldString[] = { 'W', 'O', 'R', 'L', 'D' };
	
	CRC::Table<std::uint32_t, 32> table(CRC::CRC_32());
	
	std::uint32_t crc;
	
	crc = CRC::Calculate(myHelloString, sizeof(myHelloString), table);
	crc = CRC::Calculate(myWorldString, sizeof(myWorldString), table, crc);
	
	std::cout << std::hex << crc;
	
	return 0;
}

Or, if you prefer using the auto keyword:

int main(int argc, char ** argv)
{
	const char myHelloString[] = { 'H', 'E', 'L', 'L', 'O', ' ' };
	const char myWorldString[] = { 'W', 'O', 'R', 'L', 'D' };
	
	auto table = CRC::CRC_32().MakeTable();
	
	std::uint32_t crc;
	
	crc = CRC::Calculate(myHelloString, sizeof(myHelloString), table);
	crc = CRC::Calculate(myWorldString, sizeof(myWorldString), table, crc);
	
	std::cout << std::hex << crc;
	
	return 0;
}

Lookup tables are much faster than computing a CRC bit-by-bit, at the expense of extra memory usage. A lookup table can be reused for as many CRCs as desired until it goes out of scope.

Configuration

CRC++ can be configured by setting various #defines before #include-ing the CRC++ header file:

  • #define crcpp_uint8
    Specifies the type used to store CRCs that have a width of 8 bits or less. This type is not used in CRC calculations. Defaults to ::std::uint8_t.
  • #define crcpp_uint16
    Specifies the type used to store CRCs that have a width between 9 and 16 bits (inclusive). This type is not used in CRC calculations. Defaults to ::std::uint16_t.
  • #define crcpp_uint32
    Specifies the type used to store CRCs that have a width between 17 and 32 bits (inclusive). This type is not used in CRC calculations. Defaults to ::std::uint32_t.
  • #define crcpp_uint64
    Specifies the type used to store CRCs that have a width between 33 and 64 bits (inclusive). This type is not used in CRC calculations. Defaults to ::std::uint64_t.
  • #define crcpp_size
    This type is used for loop iteration and function signatures only. Defaults to ::std::size_t.
  • #define CRCPP_USE_NAMESPACE
    Define to place all CRC++ code within the ::CRCPP namespace. Not defined by default.
  • #define CRCPP_BRANCHLESS
    Define to enable a branchless CRC implementation. The branchless implementation uses a single integer multiplication in the bit-by-bit calculation instead of a small conditional. The branchless implementation may be faster on processor architectures which support single-instruction integer multiplication. Not defined by default.
  • #define CRCPP_USE_CPP11 Define to enables C++11 features (move semantics, constexpr, static_assert, etc.). Not defined by default.
  • #define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS Define to include definitions for little-used CRCs. Not defined by default.

Build

CRC does not require a build for basic usage; simply include the header file in your project.

Unit tests and documentation can be built manually with the project files provided or automatically with CMake.

To build documentation manually:

cd doxygen
doxygen Doxyfile.dox

To build unit tests manually via Make:

# Build
cd test/prj/gcc
make [debug|release]
# Run unit tests
bin/unittest

Project files and solutions for Visual Studio 2015, 2017 and 2022 are provided in test/prj. Simply open the solution file and run the project; no additional configuration should be necessary.

CMake can also be used to build the documentation and unit tests. An out-of-source build is recommended. In this example, we will do an out-of-source build in the build directory:

mkdir -p build
cd build
cmake .. [-DBUILD_DOC=ON]
# Build and run unit tests
make tests
# Build documentation
make doxygen
# Install header file
sudo make install

Unit tests are built by default. Enable the BUILD_DOC CMake flag to also build documentation (requires Doxygen).

Documentation

https://d-bahr.github.io/CRCpp/

License

CRC++ is free to use and provided under a BSD license.

References

Catalog of CRCs: https://reveng.sourceforge.io/crc-catalogue/

5G-NR Specification 3GPP TS 38.212: https://www.etsi.org/deliver/etsi_ts/138200_138299/138212/15.03.00_60/ts_138212v150300p.pdf

USB 2.0 Specification: https://www.usb.org/document-library/usb-20-specification

crcpp's People

Contributors

clementperon avatar d-bahr avatar jdemel avatar mfoxru avatar prodygy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

crcpp's Issues

{MSVC} Building with /W4 results in warning C4127

...
\...\extern\CRCpp\inc\CRC.h(904): warning C4127: conditional expression is constant
\...\extern\CRCpp\inc\CRC.h(501): note: see reference to function template instantiation 'CRCType CRC::CalculateRemainder<CRCType,32>(const void *,size_t,const CRC::Table<CRCType,32> &,CRCType)' being compiled
        with
        [
            CRCType=uint32_t
        ]
...

Right above line 904, an MSVC warning is explicitly disabled. I wonder if the same should be done here?

Happy to create a PR if so.

Workaround is to disable it for the entire include:

#if defined( WIN32 ) || defined( _WIN32 ) || defined( WINCE )
// Disable warning about "conditional expression is constant".
#pragma warning( push )
#pragma warning( disable : 4127 )
#endif
#include "CRC.h"
#if defined( WIN32 ) || defined( _WIN32 ) || defined( WINCE )
#pragma warning( pop )
#endif

Big amount of -Wconversion warnings

Hello:
Thanks for this piece of software which I have found very helpful.
I use it in one of our projects where we happen to also use the -Wconversion gcc flag. When doing like this, a lot of warning are issued by the compiler. For instance:

In file included from ../../src/main.cpp:38:0:
../../../inc/CRC.h: In instantiation of ‘static CRCType CRC::CalculateRemainder(const void*, size_t, const CRC::Parameters<CRCType, CRCWidth>&, CRCType) [with CRCType = unsigned char; short unsigned int CRCWidth = 8u; size_t = long unsigned int]’:
../../../inc/CRC.h:438:43:   required from ‘static CRCType CRC::Calculate(const void*, size_t, const CRC::Parameters<CRCType, CRCWidth>&) [with CRCType = unsigned char; short unsigned int CRCWidth = 8u; size_t = long unsigned int]’
../../src/main.cpp:102:41:   required from ‘void CRCBitByBitTest(const char*, size_t, const CRC::Parameters<CRCType, CRCWidth>&, CRCType, const string&) [with CRCType = unsigned char; short unsigned int CRCWidth = 8u; size_t = long unsigned int; std::__cxx11::string = std::__cxx11::basic_string<char>]’
../../src/main.cpp:208:5:   required from here
../../../inc/CRC.h:624:23: warning: conversion to ‘unsigned char’ from ‘int’ may alter its value [-Wconversion]
             remainder ^= *current++;
             ~~~~~~~~~~^~~~~~~~~~~~~

Find attached the whole build log and a patch to reproduce the problem.
Steps to reproduce (on Debian Stretch but could work for other distros) :

  • Clone the repository
  • Apply patch
  • go to test/prj/gcc subdirectory
  • make

build.log
gcc-Wconversion-diff.txt

Just-in-time debugger catches access violation crash "reading location 0x004B1918"

I've been using CRCpp packaged within hidetaki's MsgPacketizer package, and my program has been crashing periodically. The just-in-time debugger I'm using points to Line 651 of CRCpp.h

        while (size--)
        {
            remainder = static_cast<CRCType>(remainder ^ (static_cast<CRCType>(*current++) << SHIFT));

Line 651 is the line beginning with "remainder = ..."

Any help would be appreciated. Trying to iron out these bugs.

HDLC/PPP CRC-16?

I'm trying to use CRCpp to generate CRC-16s using the polynomial that PPP and HDLC uses. The code is from the minihdlc Github project.

  • Polynomial is either 0x8408 or 0x8810, depending on who is ordering the bits.
  • Initial value is 0xFFFF
  • Final CRC is XORed with 0xFFFF
  • Check value is 0xF0B8

The code they use (excerpted) is:

#define lo8(x)		((x)&0xff)
#define hi8(x)		((x)>>8)
/*
 Polynomial: x^16 + x^12 + x^5 + 1 (0x8408) Initial value: 0xffff
 This is the CRC used by PPP and IrDA.
 See RFC1171 (PPP protocol) and IrDA IrLAP 1.1
 */
static uint16_t _crc_ccitt_update(uint16_t crc, uint8_t data) {
	data ^= lo8(crc);
	data ^= data << 4;

	return ((((uint16_t) data << 8) | hi8(crc)) ^ (uint8_t) (data >> 4)
			^ ((uint16_t) data << 3));
}

(Though they forget to XOR at the end and they do "CRC the data and compare to the packet CRC" instead of "CRC the data and packet CRC and compare to the check value", their code can easily be tweaked to do the latter and gives what appears to be the correct answer.)

There's also a table-based implementation in Appendix A of RFC1549. I've implemented all three versions, using a 32-element test data vector of [ 0x60, 0x61, 0x62, ... 0x7E, 0x7F ] and I get a CRC of 0x75DF with CRCpp and 0x1214 with the other two versions. For CRCpp, I'm using these parameters:

static const CRCPP::CRC::Parameters<uint16_t, 16> parameters = { 0x8408, 0xFFFF, 0xFFFF, false, false };

Any ideas what's wrong? Also, can this polynomial be added to CRCpp?

Enable CRC calculation for non-8bit multiple input size

I'd like to calculate a CRC checksum for e.g. 13 or 26 bit input.

I expect data to start with full bytes and then the last byte is not fully packed. e.g. [xxxx x000] for 13bit input. I'd like to skip the last 3 bit in a BitByBit calculation. How should I approach this?

Cmake and vcpkg support?

Even though this is a header-only library, it would be nice to be able to get it from vcpkg for simpler updating and versioning.

Do you have any experience with Cmake and vcpkg? I'm just starting to use it myself so I'm not sure I will manage to implement it on my own, but I can try to support/test it for you? When I get more familiar with Cmake and vcpkg I can maybe give it a shot myself if you can't.

Here are some examples of eigen3 and rapidjson (which are header-only too):

https://github.com/microsoft/vcpkg/tree/master/ports/eigen3
https://github.com/microsoft/vcpkg/tree/master/ports/rapidjson
https://vcpkg.readthedocs.io/en/latest/examples/packaging-github-repos/

Thank you for this excellent library!

warning: left shift count >= width of type

Hello:
After fixing #3 (thanks for that), I'm now noticing the subject warning:

../../../inc/CRC.h:753:52: warning: left shift count >= width of type [-Wshift-count-overflow]
         remainder = static_cast<CRCType>(remainder << SHIFT);

In order to reproduce I clone and update to HEAD (7421f32). I then go to test/prj/gcc and finally I issue make.
I'm on debian stretch and gcc version is:

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6.3.0-18+deb9u1' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)

build.log

can support crc32p4?

I want to use crc32p4. But I cannot find the custom Polynomial parameter to input it.

Performance of CRC32-C

Hi

first of all, thanks for this implementation, finally I can try to be independent from Boost.

I have hit a performance issue concerning a legacy codebase where CRC32-C is used. The Boost version of it, known as crc_optimal, is ~45% faster than yours, even using definitions such as CRCPP_USE_CPP11 and CRCPP_BRANCHLESS. I'd like to ditch the Boost one for this implementation, but the slowdown seems pretty hard to digest.

CRC-16 not getting expected result...

I have a hex string that gives this row on this website CRC calculator: https://crccalc.com/
image

But when I used the values from that website to check the same hexadecimal string with your library, I got a different answer... What am I doing wrong? (I'm new to CRC:s....)

The first and third output is same and second and fourth is also same.

std::cout << std::hex << calcCRC(s, CRC::CRC_16_X25()) << std::endl;
std::cout << calcCRC(hex_str_to_bin_str(s), CRC::CRC_16_X25()) << std::endl;

static const CRC::Parameters<uint16_t, 16> parameters = { 0x1021, 0xFFFF, 0xFFFF, true, true };
std::cout << std::hex << calcCRC(s, parameters) << std::endl;
std::cout << calcCRC(hex_str_to_bin_str(s), parameters) << std::endl;

My string is as follows:
A11D01000110B0AEE6E7000F4000000000022409060100000281FF09074B464D5F30303109060000600100FF09103733343031353730333035343234373609060000600107FF09074D41333034483409060100010700FF060000000309060100020700FF060000000009060100030700FF060000000009060100040700FF0600000000090601001F0700FF060000002009060100330700FF060000000009060100470700FF060000000009060100200700FF060000091209060100340700FF060000000009060100480700FF060000000009060000010000FF090C07E5031702123200FFFFC40009060100010800FF060000047609060100020800FF060000000009060100030800FF060000004309060100040800FF0600000000

The functions mentioned are pretty basic...

const char* hex_char_to_bin(char c)
{
    switch(toupper(c))
    {
        case '0': return "0000";
        case '1': return "0001";
        case '2': return "0010";
        case '3': return "0011";
        case '4': return "0100";
        case '5': return "0101";
        case '6': return "0110";
        case '7': return "0111";
        case '8': return "1000";
        case '9': return "1001";
        case 'A': return "1010";
        case 'B': return "1011";
        case 'C': return "1100";
        case 'D': return "1101";
        case 'E': return "1110";
        case 'F': return "1111";
    }
}

std::string hex_str_to_bin_str(const std::string& hex)
{
    std::string bin;
    for(unsigned i = 0; i != hex.length(); ++i)
       bin += hex_char_to_bin(hex[i]);
    return bin;
}

std::uint16_t calcCRC(std::string s, CRC::Parameters<uint16_t, (uint16_t)16U> params) {
    auto table = params.MakeTable();
    return CRC::Calculate(s.c_str(), s.length(), table);
}

Unknown pragma when compiling with MSYS MinGW

C:/.../CRC.h:896: error: ignoring '#pragma warning ' [-Werror=unknown-pragmas]
  896 | #   pragma warning (disable : 4333)
      |

Using "MinGW 13.2.0" from MSYS (C:/msys64/ucrt64/bin/g++.exe).

I guess one (or more) of these is defined when using MSYS:

#if defined(WIN32) || defined(_WIN32) || defined(WINCE)

Maybe it should be checking for MSVC explicitly instead?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.