How to assign byte[] as a pointer in C#

22,389

Solution 1

You could make the method accept a byte array:

public static unsafe byte GenerateCheckByte(byte[] packetArray, int length, UInt32 seed)
{
    fixed(byte *packet = packetArray)
    {
        ... etc
    }
}

It's better to keep the unsafe stuff hidden away as much as possible behind managed interfaces.

Then calling it would be easy:

packetBuffer[5] = Functions.GenerateCheckByte(packetBuffer, 18, ...

In fact, it would be better to write GenerateCheckByte to operate on an array anyway, instead of delving into unsafe techniques:

public static unsafe byte GenerateCheckByte(byte[] packet, int length, UInt32 seed )
{
    if (packet == null)
        throw new ArgumentNullException("packet"); // the right way in C#

    UInt32 checksum = 0xFFFFFFFF;
    length &= 0x7FFF;

    UInt32 moddedseed = seed << 8;
    for (int i = 0; i < length; i++)
        checksum = ( checksum >> 8 ) ^ Table.table[moddedseed + ( ( packet[i] ^ checksum ) & 0xFF )];
    byte result = (byte)(( (checksum>>24)&0xFF ) + ( (checksum>>8)&0xFF ) + ( (checksum>>16)&0xFF ) + ( checksum&0xFF ));
    return result;
}

Write the simplest, safest implementation you can, and only mess with pointers if you find a bottleneck in profiling.

Are you just translating a lot of existing C/C++ into C#? There's little point doing that unless you get some new safety/maintainability from it. :)

Solution 2

You shouldn't have to use unsafe code at all. If you send in a byte array to the function, it can access it without using pointers.

I haven't tested the code, but it should be something like this:

byte GenerateCheckByte(byte[] packet, ulong seed) {
    if (packet == null) return 0;
    int length = packet.Length & 0x7FFF;
    ulong checksum = 0xFFFFFFFF;
    ulong moddedseed = seed << 8;
    for (int i = 0; i < length; i++) {
            checksum = (checksum >> 8) ^ table[moddedseed + ((packet[i] ^ checksum) & 0xFF)];
    }
    return (byte)(
        ((checksum >> 24) & 0xFF) +
        ((checksum >> 16) & 0xFF) +
        ((checksum >> 8) & 0xFF) +
        (checksum & 0xFF)
    );
}

Solution 3

You need to 'pin' the byte array into memory to use it as a byte*.

byte checksum; 
fixed(byte* pPacketBuffer = packetBuffer)
{
    checksum = Functions.GenerateCheckByte(pPacketBuffer, 18, packet.seedCRC) 
}
packetBuffer[5] = checksum 

References:

Share:
22,389
P. Duw
Author by

P. Duw

Updated on August 18, 2020

Comments

  • P. Duw
    P. Duw over 3 years

    I have a function that generates a CRC check byte based on the content of any packet.The problem is in translating the function from C++ to C#

    C++ code:

    unsigned char GenerateCheckByte( char* packet, int length, unsigned long seed )
    {
    if( !packet ) return 0;
    unsigned long checksum = 0xFFFFFFFF;
    length &= 0x7FFF;
    char* ptr = packet;
    unsigned long moddedseed = seed << 8;
    for( int i = 0; i < length; i++ )
        checksum = ( checksum >> 8 ) ^ table[moddedseed + ( ( *(ptr++) ^ checksum ) & 0xFF )];
    unsigned char result = ( (checksum>>24)&0xFF ) + ( (checksum>>8)&0xFF ) + ( (checksum>>16)&0xFF ) + ( checksum&0xFF );
    return result;
    }
    

    the char*(packet) can also be defined as LPBYTE,the idea is that the value assigned to *packet is assigned to *ptr and as you see *ptr increases.Meaning a byte array is passed in and by increasing the value of the pointer it goes to the next byte.

    I tried to do it in C# and failed many times.After some hard work I figured out some code,but i can't execute it :?

    C# code

        public static unsafe byte GenerateCheckByte(byte *packet, int length, UInt32 seed )
        {
            if (*packet == 0)
            return 0;
            UInt32 checksum = 0xFFFFFFFF;
            length &= 0x7FFF;
            byte *ptr = packet;
            UInt32 moddedseed = seed << 8;
            for (int i = 0; i < length; i++)
                checksum = ( checksum >> 8 ) ^ Table.table[moddedseed + ( ( *(ptr++) ^ checksum ) & 0xFF )];
            byte result = (byte)(( (checksum>>24)&0xFF ) + ( (checksum>>8)&0xFF ) + ( (checksum>>16)&0xFF ) + ( checksum&0xFF ));
            return result;
        }
    

    It doesn't look that bad,but I can't call it

      unsafe
      {
          packetBuffer[5] = Functions.GenerateCheckByte(&packetBuffer[0], 18, packet.seedCRC);
      }
    

    error: "You can only take the address of an unfixed expression inside of a fixed statement initializer"

    Please note

    packetbuffer in both C++ and C# application is byte[] packetBuffer = new byte[18];