Search code examples
c#c++crccode-translation

How do I translate my code from C# to C++ for a CRC function?


I have the following code in C# to calculate a CRC and it works like I want it to.

 public byte crc_8(byte[] byteArray)
    {
        ushort reg_crc = 0;
        for(int i = 0; i<byteArray.Length; i++)
        {
            reg_crc ^= byteArray[i];
            for(int j = 0; j < 8; j++)
            {
                if((reg_crc & 0x01) == 1)
                {
                    reg_crc = (ushort)((reg_crc >> 1) ^ 0xE5);
                }
                else
                {
                    reg_crc = (ushort)(reg_crc >> 1);
                }
            }
        }
        reg_crc = (byte)(reg_crc & 0xFF);
        return (byte)reg_crc;
    } 

I also need to add this same function to a code project that is in C++, but I am brand new to C++. This is as far as I have gotten, and I am not sure with how to proceed with the code inside of the for loop. Also note that RX_PACKET_SIZE is equivalent to byteArray.Length in that it can be used for the same purpose. I know that is okay.

static uint8_t crc_8(unit8_t array_to_process [])
{
    uint16_t reg_crc = 0;
    for(int i = 0; i < RX_PACKET_SIZE; i++)
    {

    }
}

Solution

  • Arrays work a bit differently in C++. They're not objects; they're basically just a datatype repeated in memory n times. In your case, it'd be a uint_8 repeated RX_PACKET_SIZE times. You don't pass the array itself; instead, you pass a pointer to the first element of the array. This is the C++ version of your code:

    uint8_t crc_8(uint8_t* byteArray, size_t length)
    {
        uint8_t reg_crc = 0;
        for(int i = 0; i < length; i++)
        {
            reg_crc ^= byteArray[i];
            for(int j = 0; j < 8; j++)
            {
                if((reg_crc & 0x01) == 1)
                {
                    reg_crc = (reg_crc >> 1) ^ 0xE5;
                }
                else
                {
                    reg_crc = reg_crc >> 1;
                }
            }
        }
        return reg_crc;
    }
    

    I changed the type of reg_crc to uint8_t because none of the operations you perform on it ever used the latter half of the bits. Given that you know the length is RX_PACKET_SIZE, we can also give length a default value:

    uint8_t crc_8(uint8_t* byteArray, size_t length = RX_PACKET_SIZE)
    {
        uint8_t reg_crc = 0;
        for(int i = 0; i < length; i++)
        {
            reg_crc ^= byteArray[i];
            for(int j = 0; j < 8; j++)
            {
                if((reg_crc & 0x01) == 1)
                {
                    reg_crc = (reg_crc >> 1) ^ 0xE5;
                }
                else
                {
                    reg_crc = reg_crc >> 1;
                }
            }
        }
        return reg_crc;
    }
    

    Helpful note for the future:

    The C++ standard library provides a class called std::vector. std::vector has the same abilities that an ArrayList does in C#, but because of the way C++ templates work, it'll likely be faster.

    You can write an overload for crc_8 so that you can just pass it a vector:

    // The & after std::vector<uint8_t> means that it'll pass 
    // by reference, instead of passing by value. Passing by  
    // reference is usually the preferable option because nothing
    // gets copied, making it much faster. 
    uint8_t crc_8(std::vector<uint8_t>& bytes) {
        //This calls the the version shown above
        return crc_8(bytes.data(), bytes.size());
    }
    

    If the compiler says that uint8_t isn't defined, it's because you need to put #include <cstdint> at the top of the file.