【发布时间】:2021-10-22 07:32:14
【问题描述】:
我正在尝试将一些 C++ 代码转换为 C# 以用于应用程序。我试图转换的函数计算对象的校验和,其中包括 MAC 地址以及其他详细信息。 C++中的校验和函数定义为:
unsigned short CalculateCheckSum(unsigned char* p, int n)
{
unsigned short x, checksum = 0;
for (unsigned long i = 0; i < n; ++i)
{
x = p[i];
x <<= i % 8;
checksum += x;
}
return checksum != 0 ? checksum : 51;
我写的C#中定义的函数是:
public static ushort CalculateCheckSum(byte[] p, int n)
{
ushort x, checksum = 0;
for (int i = 0; i < n; ++i)
{
x = p[i];
x <<= i % 8;
checksum += x;
}
return (ushort)(checksum != 0 ? checksum : 51);
}
下面是用 C++ 计算校验和的代码:
PCInfoClass pcInfo;
char nicIDStr[1024];
strcpy_s(nicIDStr, "34-29-8f-93-16-61");
NICAddressStrToBinary(nicIDStr, pcInfo.nicID);
char outbuf[1000];
pcInfo.timeStamp = 1234;
pcInfo.expDate = 0;
I32 pcInfoSz = 20;
pcInfo.checksum = 0;
unsigned char* byteStr;
byteStr = (unsigned char*)&pcInfo;
pcInfo.checksum = CalculateCheckSum(byteStr, pcInfoSz);
由于 CalculateCheckSum 方法采用 Byte 数组作为参数,因此我使用了 System.Runtime 附带的 BinaryFormatter 类。我尝试使用以下几行在 C# 中复制相同的功能:
PCInfoClass pcInfo = new PCInfoClass();
char[] nicIDStr = new char[1024];
string str = "34-29-8f-93-16-61";
for (int i = 0; i < str.Length; i++)
{
nicIDStr[i] = str[i];
}
NICAddressStrToBinary(nicIDStr, pcInfo.nicID);
pcInfo.timeStamp = 1234;
pcInfo.expDate = 0;
int pcInfoSz = 20;
pcInfo.checksum = 0;
pcInfo.checksum = CalculateCheckSum(ObjectToByteArray1(pcInfo), pcInfoSz);
public static byte[] ObjectToByteArray1(Object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
不幸的是,两种方法的校验和值不同,因此转换在这一点上卡住了。
此代码中使用的另一个方法是 NICAddressStrToBinary,在 C++ 中其定义为:
bool NICAddressStrToBinary(const char* nicIDStr, unsigned char* outbuf)
{
int c, i, dgt;
if (nicIDStr == NULL) return false;
//converted char to integer as ascii number.
for (dgt = 0, i = 0; (c = nicIDStr[i]) != '\0'; ++i)
{
//if it is 45 '-' then the loop will continue;
if (c == '-') continue;
//if the ascii value is between 48 to 57 then we will decrrease with 48 of given integer
if ('0' <= c && c <= '9')
{
c -= '0';
}
else
if ('a' <= c && c <= 'f')
{
c -= 'a' - 10;
}
else
if ('A' <= c && c <= 'F')
{
c -= 'A' - 10;
}
else
{
return false;
}
if (dgt >= 6 * 2)
{
return false;
}
if (outbuf != NULL)
{
if ((dgt & 1) == 0)
{
//// it means c<<4 is c*2power4
outbuf[dgt / 2] = c << 4;
}
else
{
outbuf[dgt / 2] |= c;
}
}
dgt++;
}
if (dgt < 6 * 2)
{
return false;
}
return true;
}
在 C# 中它被重写为:
public static void NICAddressStrToBinary(char[] nicIDStr, byte[] outbuf)
{
int c, i, dgt;
if (nicIDStr == null) return ;
for (dgt = 0, i = 0; i<=nicIDStr.Length-1; ++i)
{
c = nicIDStr[i];
if (c == '-') continue;
if ('0' <= c && c <= '9')
{
c -= '0';
}
else if ('a' <= c && c <= 'f')
{
c -= 'a' - 10;
}
else if ('A' <= c && c <= 'F')
{
c -= 'A' - 10;
}
else
{
return;
}
/* make sure there aren't too many digits
*/
if (dgt >= 6 * 2)
{
return ;
}
/* accumulate the binary NIC ID
* remembering that we're starting
* with the most significant digits first
*/
if (outbuf != null)
{
if ((dgt & 1) == 0)
{
//// it means c<<4 is c*2power4
outbuf[dgt / 2] = (byte)(c << 4);
}
else
{
outbuf[dgt / 2] |= (byte)c;
}
}
/* advance the digit index
*/
dgt++;
}
/* make sure I have enough digits
*/
if (dgt < 6 * 2)
{
return ;
}
return ;
}
谁能告诉我在 C++ 和 C# 中计算不同值的原因是什么?
【问题讨论】:
-
代码太多了!很高兴您发布了所有相关代码,但您可以尝试减少可能存在问题的代码量(通过测试较小的部分,以确定它们在两个程序中是否相同)。要么你会以这种方式找到它,要么你会有一个较小的问题,因此即使开始回答也不会那么令人生畏。还是只有第一个 sn-p 错了?
-
嗨,很抱歉我在这里倾倒的代码量!我不想遗漏任何细节,但我确实认为问题可能与将对象转换为字节数组有关。在 C++ 中,旧代码只执行
byteStr = (unsigned char*)&pcInfo;,但在 C# 中,我使用了相同的库。我不确定如何确保它们是相同的。 -
不相关的;当你最终得到像
i<=nicIDStr.Length-1;这样的东西时,可以为自己和编译器节省一些精力并将其重写为i<nicIDStr.Length;。为像我这样的人节省了一些精力,因为当我在 for 循环退出条件中看到<=时,我开始寻找它通常会导致的错误。这段代码使用 -1 修复了错误,但是如果长度为零怎么办?如果出现无符号下溢,i <= -1可能需要很长时间才能变为真。 -
谢谢,我会记住的。