C# Byte[] 到 BCD 和 BCD 到 INT

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11701043/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 18:53:27  来源:igfitidea点击:

C# Byte[] to BCD and BCD to INT

c#arraysbytebcd

提问by xFireTR

I have a Hex file created by CashRegister Machine. I have to read this file in.

我有一个由 CashRegister Machine 创建的 Hex 文件。我必须读入这个文件。

File uses formatting detailed below. It is like socket packets.

文件使用下面详述的格式。它就像套接字数据包。

Code Data : 2 Byte
PLU Code Data: 7 Byte
Unit Price Data: 5 Byte
Quantity Data: 5 Byte
Total Amount Data: 5 Byte
PLU Name Data: 18 Byte
Tax Rate Data: 1 Byte
Length: 24 + 19 Byte

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

  • PLU code format is BCD
  • Unit price 1-9999999999 (BCD)
  • quantity 1-9999999999 (BCD last 3 numbers should be decimal)
  • total amount 1-9999999999 (BCD)
  • PLU 编码格式为 BCD
  • 单价 1-9999999999 (BCD)
  • 数量 1-9999999999(BCD 后 3 个数字应为十进制)
  • 总金额1-9999999999(BCD)

I read in the hex file with a binary reader and then insert int the Unit Price byte array.

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

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

This array is Unit Price. But how can I then convert this number to decimal. And the information says that for quantity : BCD last number should be decimal--what does this mean? Thanks.

这个数组是单价。但是我怎么能把这个数字转换成十进制。并且信息说对于数量:BCD最后一个数字应该是十进制 - 这是什么意思?谢谢。

回答by hatchet - done with SOverflow

A BCD number encodes a value from 0-9 into 4 bits. In packed BCD (probably what you're dealing with), a byte is used to contain two values 0-9, one in each nibble (4 bits) of the byte. To convert to an int, you have to do a little bit fiddling. For example, the following would convert an array of BCD bytes into an int, which can hold up to 9 digits. Use long if you have more than 9 bcd digit of input.

BCD 数字将 0-9 之间的值编码为 4 位。在打包的 BCD(可能是您正在处理的内容)中,一个字节用于包含两个值 0-9,该字节的每个半字节(4 位)中都有一个。要转换为 int,您必须进行一些操作。例如,以下代码会将 BCD 字节数组转换为 int,最多可容纳 9 位数字。如果输入的 bcd 位数超过 9 位,请使用 long。

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

This assumes that each byte is stored as big-endian BCD, where the most significant digit is in the most significant nibble of the byte. This is what is described in the Wikipedia page for BCDas the more common implementation. If you are dealing with little-endian BCD, the conversion code within the for loop would be

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

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

You also need to ensure you have the correct endianness of your array, i.e., does the first byte in the array contain the most significant two digits, or the least significant two digits. For example, the number 123456 would fit into 3 bytes using packed BCD. Is 12 in byte[0] or byte[2]? You would need to adjust the loop above to reverse the order if your endianness is different than my assumption. I'm assuming 12 is in byte[0] (big endian, with the most significant digits in the leftmost byte).

您还需要确保数组的字节顺序正确,即数组中的第一个字节是否包含最高有效的两位数字,或最低有效的两位数字。例如,数字 123456 将适合使用压缩 BCD 的 3 个字节。byte[0] 或 byte[2] 是 12 吗?如果您的字节顺序与我的假设不同,则需要调整上面的循环以颠倒顺序。我假设 12 在字节 [0] 中(大端,最左边的字节是最重要的数字)。

As for the quantity described as BCD and decimal, I would need to see actual values to understand what they're talking about.

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

回答by SpacedMonkey

Each byte is two decimal digits, one in each nibble. If you show the bytes as hex, you can read the number easily.

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

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

You can get the high and low nibbles like this:

您可以像这样获得高低半字节:

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

Convert each byte into number like this:

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

int number = 10 * high + low;

But remember that each byte is 100 times bigger then the next byte.

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

With quantity having 3 decimal places, just divide the final number by 1,000 to get the actual value.

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

回答by Tyrant

CORRECT code:

正确的代码:

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

You can also create a custom extension to a byte[] by creating a public static class:

您还可以通过创建一个公共静态类来创建一个 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);

    }
}

回答by Saleh Omar

My response might be a little bit late for the question but here is how I solved the question:

我对这个问题的回答可能有点晚,但这是我解决问题的方法:

1- First I needed to find the length of the number e.g: 3422 -> 4, 100 -> 3

1- 首先我需要找到数字的长度,例如:3422 -> 4, 100 -> 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;
    }
}

After that I have split the number into an array which makes it easier to traverse and process the number. There is one caveat though, if the number is of odd length then a zero has to be added to the beginning of the array.

之后,我将数字拆分为一个数组,这样可以更轻松地遍历和处理数字。但是有一个警告,如果数字是奇数长度,则必须在数组的开头添加一个零。

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

回答by da jowkar

i wrote this code and works for me:

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

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

This is reverse code:

这是反向代码:

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

And this is test code:

这是测试代码:

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