【问题标题】:How to assign byte[] as a pointer in C#如何在 C# 中将 byte[] 分配为指针
【发布时间】:2009-03-28 22:59:46
【问题描述】:

我有一个函数可以根据任何数据包的内容生成一个 CRC 校验字节。问题在于将函数从 C++ 转换为 C#

C++ 代码:

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;
}

char*(packet) 也可以定义为 LPBYTE,这个想法是分配给 *packet 的值被分配给 *ptr 并且正如你所看到的 *ptr 增加。意味着传入一个字节数组并通过增加指向下一个字节的指针的值。

我尝试在 C# 中进行,但多次失败。经过一番努力,我想出了一些代码,但我无法执行:?

C#代码

    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;
    }

看起来没那么糟糕,但我不能称之为

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

错误:“您只能在固定语句初始化程序中获取未固定表达式的地址”

请注意

C++ 和 C# 应用程序中的数据包缓冲区是 byte[] packetBuffer = new byte[18];

【问题讨论】:

    标签: c# pointers byte


    【解决方案1】:

    你可以让方法接受一个字节数组:

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

    最好将不安全的东西尽可能隐藏在托管接口后面。

    然后调用它会很容易:

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

    其实还是写GenerateCheckByte来操作数组会更好,而不是钻研unsafe技术:

    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;
    }
    

    尽可能编写最简单、最安全的实现,并且只有在发现性能分析瓶颈时才使用指针。

    您是否只是将大量现有的 C/C++ 转换为 C#?除非您从中获得一些新的安全性/可维护性,否则这样做毫无意义。 :)

    【讨论】:

      【解决方案2】:

      您根本不必使用不安全的代码。如果你向函数发送一个字节数组,它可以在不使用指针的情况下访问它。

      我没有测试过代码,但应该是这样的:

      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)
          );
      }
      

      【讨论】:

        【解决方案3】:

        您需要将字节数组“固定”到内存中才能将其用作字节*。

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

        参考文献:

        【讨论】:

          猜你喜欢
          • 2023-04-09
          • 2021-08-14
          • 2016-12-03
          • 1970-01-01
          • 2016-03-03
          • 1970-01-01
          • 2018-08-11
          • 2022-07-06
          • 2020-08-18
          相关资源
          最近更新 更多