C#字节[]到BCD,BCD到INT

本文关键字:BCD INT 字节 | 更新日期: 2024-08-01 22:17:04

我有一个由CashRegister Machine创建的十六进制文件。我必须在.中阅读这个文件

文件使用以下详细说明的格式。它就像套接字包。

代码数据:2字节
PLU代码数据:7字节
单价数据:5字节
数量数据:5字节
总量数据:5字节
PLU名称数据:18字节
税率数据:1字节
长度:24+19字节

  • PLU代码格式为BCD
  • 单价1-9999999999(BCD)
  • 数量1-9999999999(BCD最后3个数字应为十进制)
  • 总额1-9999999999(BCD)

我用二进制读取器读取十六进制文件,然后插入int单价字节数组。

byte[] bytes = { data[21], data[22], data[23], data[24], data[25] }; // BCD Byte Array

此数组为单价。但是我怎么能把这个数字转换成十进制呢。信息表明,对于数量:BCD最后一个数字应该是十进制的——这意味着什么?谢谢

C#字节[]到BCD,BCD到INT

BCD数字将0-9的值编码为4位。在压缩BCD(可能是您正在处理的)中,一个字节用于包含两个值0-9,每个字节的半字节(4位)中有一个值。要转换成int,你必须做一些小动作。例如,下面将把一个BCD字节数组转换为int,最多可容纳9位数字。如果输入超过9 bcd位数,请使用long。

// assume byte[] bcds is input
int result = 0;
foreach(byte bcd in bcds) {
    result *= 100;
    result += (10 * (bcd >> 4));
    result += bcd & 0xf;
}

这假设每个字节都存储为大端BCD,其中最高有效位在字节的最高有效半字节中。这就是维基百科页面中描述的BCD更常见的实现。如果您正在处理小端BCD,for循环中的转换代码将是

    result *= 100;
    result += (10 * (bcd & 0xf));
    result += bcd >> 4;

您还需要确保数组的端序正确,即数组中的第一个字节包含最高有效的两位数字还是最低有效的两位数。例如,使用压缩BCD,数字123456可以容纳3个字节。12在字节[0]还是在字节[2]中?如果你的endianness与我的假设不同,你需要调整上面的循环来颠倒顺序。我假设12在字节[0]中(big-endian,最高有效数字在最左边的字节中)。

至于描述为BCD和十进制的数量,我需要看到实际值来理解他们在说什么。

每个字节是两个十进制数字,每个半字节一个。如果将字节显示为十六进制,则可以轻松读取数字。

0x08 0x27 0x42 0x17 0x75 = 827,421,775

你可以得到这样的高和低蚕食:

int high = currentByte >> 4;
int low = currentByte & 0xF;

将每个字节转换为数字,如下所示:

int number = 10 * high + low;

但请记住,每个字节都比下一个字节大100倍。

数量有3位小数,只需将最终数字除以1000即可得到实际值。

正确代码:

// assume byte[] bcds is input
int result = 0;
foreach(byte bcd in bcds) {
    result *= 100;
    result += (10 * (bcd >> 4));
    result += bcd & 0xf;
}

您还可以通过创建一个公共静态类来创建byte[]的自定义扩展:

public static class BitConverterExtension
{
    public static UInt64 FromBCDToExtUInt64(this byte[] b, byte[] bcds, uint nBytes, uint startOf)
    {
        UInt64 result = 0;
        uint i = 0;
        for (i = 0; i < nBytes; i++)
        {
            result *= 100;
            result += (UInt64)(10 * (bcds[startOf + i] >> 4));
            result += (UInt64)(bcds[startOf + i] & 0xf);
        }
        return (result);
    }
}

我写了这段代码并为我工作:

 public uint BCD5ToInt(byte [] bcd)
{
uint outInt=0;
   for (int i = 0; i < bcd.Length; i++)
   {
       int mul = (int)Math.Pow(10,(i*2));
       outInt += (uint) (((bcd[i] & 0xF)) * mul);
       mul = (int)Math.Pow(10, (i * 2) + 1);
       outInt +=(uint)( ((bcd[i] >> 4) ) * mul);
   }
   return outInt;
}

这是反向代码:

  // Convert an unsigned integer into 5 bytes of 
    public byte[] IntToBCD5(uint numericvalue, int bytesize = 5)
    {
        byte[] bcd = new byte[bytesize];
        for (int byteNo = 0; byteNo < bytesize; ++byteNo)
            bcd[byteNo] = 0;
        for (int digit = 0; digit < bytesize * 2; ++digit)
        {
            uint hexpart = numericvalue % 10;
            bcd[digit / 2] |= (byte)(hexpart << ((digit % 2) * 4));
            numericvalue /= 10;
        }
        return bcd;
    }

这是测试代码:

 public void test()
    {
        uint firstInt = 987654321;
        var array = IntToBCD5(firstInt);
        var outInt = BCD5ToInt(array);
        MessageBox.Show(outInt.ToString());
    }

我的回答可能有点晚,但以下是我解决问题的方法:

1-首先我需要找到数字的长度,例如:3422->4100->3

public static class NumbersUtility
{
    public static int FindNumberLength(int number)
    {
        return Convert.ToInt32( Math.Floor(Math.Log(number,10))+1);
    }
    public static int FindNumberDivisor(int number)
    {
        return Convert.ToInt32(Math.Pow(10, FindNumberLength(number)-1));
    }
    public static int[] FindNumberElements(int number)
    {
        int[] elements = new int[FindNumberLength(number)];
        int divisor = FindNumberDivisor(number);
        for (int i = 0; i < elements.Length; i++)
        {
            elements[i] = number/divisor;
            number %= divisor;
            divisor /= 10;
        }
        return elements;
    }
}

之后,我将数字拆分为一个数组,这样可以更容易地遍历和处理数字。不过,有一点需要注意,如果数字的长度为奇数,则必须在数组的开头添加一个零。

       public static byte[] IntToBCD(int[] input, bool isLittleEndian = false)
    {
        byte[] outArr = new byte[Convert.ToInt32(Math.Ceiling((double) input.Length/2))];
        //Handle the case of an odd number in which a zero should be added at the beginning
        if (input.Length%2 != 0)
        {
            //Use a temp array to expand the old one, you can use lists or 
            //anyother datastructure if you wish to
            int[] newInput = new int[input.Length+1];
            Array.Copy(input,0,newInput,1,input.Length);
            newInput[0] = 0;
            input = newInput;
            //Dispose the temp array
            newInput = null;
        }
        for (int i = 0; i < outArr.Length; i++)
        {
            outArr[i]=(byte)(input[i*2]<<4);
            outArr[i]|=(byte)(input[i*2+1]);
        }
        return outArr;
    }