문제
모든 패킷의 내용을 기반으로 CRC Check Byte를 생성하는 함수가 있습니다. 문제는 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 *(패킷)는 lpbyte로 정의 될 수 있습니다. 아이디어는 *패킷에 할당 된 값이 *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# 응용 프로그램의 PacketBuffer는 BYTE [] PACKETBUFFER = NEW BYTE [18]입니다.
해결책
메소드가 바이트 배열을 수락 할 수 있습니다.
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#으로 번역하고 있습니까? 새로운 안전/유지 가능성을 얻지 않으면 그 점이 거의 없습니다. :)
다른 팁
안전하지 않은 코드를 전혀 사용할 필요가 없습니다. 바이트 배열을 함수로 보내면 포인터를 사용하지 않고 액세스 할 수 있습니다.
코드를 테스트하지는 않았지만 다음과 같은 것이어야합니다.
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)
);
}
바이트*로 사용하려면 바이트 배열을 메모리에 '고정'해야합니다.
byte checksum;
fixed(byte* pPacketBuffer = packetBuffer)
{
checksum = Functions.GenerateCheckByte(pPacketBuffer, 18, packet.seedCRC)
}
packetBuffer[5] = checksum
참조 :