I am trying to convert a short type into 2 bytes type for store in a byte array, here is the snippet thats been working well "so far".
if (type == "short")
{
size = data.size;
databuffer[index+1] = (byte)(data.numeric_data >> 8);
databuffer[index] = (byte)(data.numeric_data & 255);
return size;
}
Numeric_data is int type. It all worked well till i process the value 284 (decimal). It turns out that 284 >> 8 is 1 instead of 4.
The main goal is to have:
byte[0] = 28
byte[1] = 4
Is this what you are looking for:
static void Main(string[] args)
{
short data=284;
byte[] bytes=BitConverter.GetBytes(data);
// bytes[0] = 28
// bytes[1] = 1
}
Just for fun:
public static byte[] ToByteArray(short s)
{
//return, if `short` can be cast to `byte` without overflow
if (s <= byte.MaxValue)
return new byte[] { (byte)s };
List<byte> bytes = new List<byte>();
byte b = 0;
//determine delta through the number of digits
short delta = (short)Math.Pow(10, s.ToString().Length - 3);
//as soon as byte can be not more than 3 digits length
for (int i = 0; i < 3; i++)
{
//take first 3 (or 2, or 1) digits from the high-order digit
short temp = (short)(s / delta);
if (temp > byte.MaxValue) //if it's still too big
delta *= 10;
else //the byte is found, break the loop
{
b = (byte)temp;
break;
}
}
//add the found byte
bytes.Add(b);
//recursively search in the rest of the number
bytes.AddRange(ToByteArray((short)(s % delta)));
return bytes.ToArray();
}
this recursive method does what the OP need with at least any positive short value.
Why would 284 >> 8 would be 4?
Why would 284 be split in two bytes equal to 28 and 4?
The binary representation of 284 is 0000 0001 0001 1100. As you can see, there are two bytes (eight bits) which are 0000 0001 (256 in decimal) and 0001 1100 (28 in decimal).
284 >> 8 is 1 (0000 0001) and it is correct.
284 should be split in two bytes equal to 256 and 24.
You conversion is correct!
If you insist:
short val = 284;
byte a = (byte)(val / 10);
byte b = (byte)(val % 10);
Disclaimer:
This does not make much sense, but it is what you want. I assume you want values from 0 to 99. The logical thing to do would be to use 100 as the denominator and not 10. But then again, I have no idea what you want to do.
Drop the nonsense conversion you are using and go for System.BitConverter.ToInt16
//to bytes
var buffer = System.BitConverter.GetBytes(284); //your short value
//from bytes
var value = System.BitConverter.ToInt16(buffer, 0);
Related
So I have two 4 bits number (between 0 and 15):
int a = 1;
int b = 15;
And I want to store them into 1 byte.
This is what I have try:
byte[] bytesA = BitConverter.GetBytes(a);
byte[] bytesB = BitConverter.GetBytes(b);
byte a = bytesA[0];
byte b = bytesB[1];
Sins a byte is 8 bits and you have 2 4 bit values, you will need to shift one of the values to occupy the high 4 bits of the resulting byte, like so:
byte ab = (byte)((a << 4) | (b & 0xF));
To get a out of ab:
byte a = (byte)((ab >> 4) & 0xF);
To get b out of ab:
byte b = (byte)(ab & 0xF);
I am looking for a method that will enable me to get a range of bits. For example if I have the binary data
0 1 0 1 1 0 1 1 1 1 0 1 0 1 1 1 (2 bytes)
I might need to get data from range bit 3 to 9. In other words I would be interested in:
0 1 0 1 1 0 1 1 1 1 0 1 0 1 1 1
so in short I will like to construct the method:
byte[] Read(byte[] data, int left, int right){
// implementation
}
so that if I pass the data new byte[]{91,215}, 3, 9 I will get byte[]{122} (note byte 91 and 215 = 0 1 0 1 1 0 1 1 1 1 0 1 0 1 1 1 and byte 122 = 1 1 1 1 0 1 0 same binary data as the example.
It would be nice if I could use the << operator on byte arrays such as doing something like:
byte[] myArray = new byte[] { 1, 2, 3 };
var shift = myArray << 2;
If you are interested to know why I need this functionality:
I am creating a project on a board and often need to read and write values to the memory. The cdf, sfr, or ddf (refereed to as chip definition file) contains information about a particular chip. That file may look like:
; Name Zone Address Bytesize Displaybase Bitrange
; ---- ---- ------- -------- ----------- --------
sfr = "SPI0_CONTROL" , "Memory", 0x40001000, 4, base=16
sfr = "SPI0_CONTROL.SPH" , "Memory", 0x40001000, 4, base=16, bitRange=25-25
sfr = "SPI0_CONTROL.SPO" , "Memory", 0x40001000, 4, base=16, bitRange=24-24
sfr = "SPI0_CONTROL.TXRXDFCOUNT" , "Memory", 0x40001000, 4, base=16, bitRange=8-23
sfr = "SPI0_CONTROL.INT_TXUR" , "Memory", 0x40001000, 4, base=16, bitRange=7-7
sfr = "SPI0_CONTROL.INT_RXOVF" , "Memory", 0x40001000, 4, base=16, bitRange=6-6
Since I am reading a lot of variables (sometimes 80 times per second) I will like to have an efficient algorithm. I guess my approach would be that if the bytesize is 8 then I will create a long from those 8 bytes then use the << and >> operators in order to get what I need. if the bytesize if 4 then I will create an int and use the << and >> operators but How will I do it if I need to read 16 bytes though? I guess my question should been how to implement the << and >> operators on custom struct types.
You need the BitArray class from System.Collections.
Looks like you could help a "bit stream". There is an implementation of such a concept here. Take a look, perhaps it fits your needs.
The BigInteger class in .NET 4+ takes a Byte[] in its constructor and has left and right shift operators.
It's been 10 years since this question and I could not yet find a simple C# implementation that extracts a range of bits from a byte array using bitwise operations.
Here's how you can do it using simple bitwise operations:
public static class ByteExtensions
{
public const int BitsPerByte = 8;
/// <summary>
/// Extracts a range of bits from a byte array into a new byte array.
/// </summary>
/// <param name="bytes">The byte array to extract the range from.</param>
/// <param name="start">The 0-based start index of the bit.</param>
/// <param name="length">The number of bits to extract.</param>
/// <returns>A new <see cref="byte"/> array with the extracted bits.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="start"/> or <paramref name="length"/> are out of range.</exception>
public static byte[] GetBitRange(this byte[] bytes, int start, int length)
{
// Calculate the length of the input byte array in bits
int maxLength = bytes.Length * BitsPerByte;
int end = start + length;
// Range validations
if (start >= maxLength || start < 0)
{
throw new ArgumentOutOfRangeException(nameof(start), start, $"Start must non-negative and lesser than {maxLength}");
}
if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length), length, $"Length must be non-negative");
}
if (end > maxLength)
{
throw new ArgumentOutOfRangeException(nameof(length), length, $"Range length must be less than or equal to {maxLength}");
}
// Calculate the length of the new byte array and allocate
var (byteLength, remainderLength) = Math.DivRem(length, BitsPerByte);
byte[] result = new byte[byteLength + (remainderLength == 0 ? 0 : 1)];
// Iterate through each byte in the new byte array
for (int i = 0; i < result.Length; i++)
{
// Compute each of the 8 bits of the ith byte
// Stop if start index >= end index (rest of the bits in the current byte will be 0 by default)
for (int j = 0; j < BitsPerByte && start < end; j++)
{
var (byteIndex, bitIndex) = Math.DivRem(start++, BitsPerByte); // Note the increment(++) in start
int currentBitIndex = j;
result[i] |= (byte)(((bytes[byteIndex] >> bitIndex) & 1) << currentBitIndex);
}
}
return result;
}
}
Explanation
1. Allocate a new byte[] for the range
The GetBitRange(..) method above first (after validation) calculates the length of the new byte array(length in bytes) using the length parameter(length in bits) and allocates this array(result).
The outer loop iterates through each byte in result and the inner loop iterates through each of the 8 bits in the ith byte.
2. Extracting a bit from a byte
In the inner loop, the method calculates the index of the byte in the input array bytes which contains the bit indexed by start. It is the bitIndexth bit in the byteIndexth byte. To extract this bit, you perform the following operations:
int nextBit = (bytes[byteIndex] >> bitIndex) & 1;
Shift the bitIndexth bit in bytes[byteIndex] to the rightmost position so it is the least significant bit(LSB). And then perform a bitwise AND with 1. (A bitwise AND with 1 extracts only the LSB and makes the rest of the bits 0.)
3. Setting a bit in a byte
Now, nextBit is the next bit I need to add to my output byte array(result). Since, I'm currently working on the jth bit of my ith byte of result in my inner loop, I need to set that bit to nextBit. This is done as:
int currentBitIndex = j;
result[i] |= (byte) (nextBit << currentBitIndex);
Shift nextBit j times to the left (since I want to set the jth bit). Now to set the bit, I perform a bitwise OR between the shifted bit and result[i]. This sets the jth bit in result[i].
The steps 2 & 3 described above are implemented in the method as a single step:
result[i] |= (byte)(((bytes[byteIndex] >> bitIndex) & 1) << currentBitIndex);
Two important things to consider here:
Byte Endianness
Bit Numbering
Byte Endianness
The above implementation indexes into the input byte array in big endian order. So, as per the example in the question,
new byte[]{ 91 , 215 }.GetBitRange(3, 8)
does not return 122 but returns 235 instead. This is because the example in the question expects the answer in little-endian format.
To use little-endian format, a simple reversal of the output array does the job. Even better is to change byteIndex in the implementation:
byteIndex = bytes.Length - 1 - byteIndex;
Bit Numbering
Bit numbering determines if the least significant bit is the first bit in the byte (LSB 0) or the most significant bit is the first bit (MSB 0).
The implementation above assumes LSB0 bit numbering.
To use MSB0, change the bit indices as follows:
currentBitIndex = BitsPerByte - 1 - currentBitIndex;
bitIndex = BitsPerByte - 1 - bitIndex;
Extending for endianness and bit numbering
Here is the full method supporting both types of endianness as well as bit numbering:
public enum Endianness
{
BigEndian,
LittleEndian
}
public enum BitNumbering
{
Lsb0,
Msb0
}
public static class ByteExtensions
{
public const int BitsPerByte = 8;
public static byte[] GetBitRange(
this byte[] bytes,
int start,
int length,
Endianness endianness,
BitNumbering bitNumbering)
{
// Calculate the length of the input byte array in bits
int maxLength = bytes.Length * BitsPerByte;
int end = start + length;
// Range validations
if (start >= maxLength || start < 0)
{
throw new ArgumentOutOfRangeException(nameof(start), start, $"Start must non-negative and lesser than {maxLength}");
}
if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length), length, $"Length must be non-negative");
}
if (end > maxLength)
{
throw new ArgumentOutOfRangeException(nameof(length), length, $"Range length must be less than or equal to {maxLength}");
}
// Calculate the length of the new byte array and allocate
var (byteLength, remainderLength) = Math.DivRem(length, BitsPerByte);
byte[] result = new byte[byteLength + (remainderLength == 0 ? 0 : 1)];
// Iterate through each byte in the new byte array
for (int i = 0; i < result.Length; i++)
{
// Compute each of the 8 bits of the ith byte
// Stop if start index >= end index (rest of the bits in the current byte will be 0 by default)
for (int j = 0; j < BitsPerByte && start < end; j++)
{
var (byteIndex, bitIndex) = Math.DivRem(start++, BitsPerByte); // Note the increment(++) in start
int currentBitIndex = j;
// Adjust for MSB 0
if (bitNumbering is BitNumbering.Msb0)
{
currentBitIndex = 7 - currentBitIndex;
bitIndex = 7 - bitIndex;
}
// Adjust for little-endian
if (endianness is Endianness.LittleEndian)
{
byteIndex = bytes.Length - 1 - byteIndex;
}
result[i] |= (byte)(((bytes[byteIndex] >> bitIndex) & 1) << currentBitIndex);
}
}
return result;
}
}
How do I convert DateTime(yyyyMMddhhmm) to a packed bcd (size 6) representation on c# ?
using System;
namespace Exercise
{
internal class Program
{
private static void Main(string[] args)
{
byte res = to_bcd(12);
}
private static byte to_bcd(int n)
{
// extract each digit from the input number n
byte d1 = Convert.ToByte(n/10);
byte d2 = Convert.ToByte(n%10);
// combine the decimal digits into a BCD number
return Convert.ToByte((d1 << 4) | d2);
}
}
}
The result you get on res variable is 18.
Thanks!
What you get is correct 18==12(Hex) as you passed to to_bcd.
static byte[] ToBCD(DateTime d)
{
List<byte> bytes = new List<byte>();
string s = d.ToString("yyyyMMddHHmm");
for (int i = 0; i < s.Length; i+=2 )
{
bytes.Add((byte)((s[i] - '0') << 4 | (s[i+1] - '0')));
}
return bytes.ToArray();
}
I'll give a short example to demonstrate the idea. You can extend this solution to your whole date format input.
The BCD format encapsulates exactly two decimal digits into one 8-bit number. For example, the representation of 92 would be, in binary:
1001 0010
or 0x92 in hex. This happens to be 146 when converted to decimal.
The code to do this would need to shift the first digit left by 4 bits and then combine with the second digit. So:
byte to_bcd(int n)
{
// extract each digit from the input number n
byte d1 = n / 10;
byte d2 = n % 10;
// combine the decimal digits into a BCD number
return (d1 << 4) | d2;
}
I'm trying to convert 3 bytes to signed integer (Big-endian) in C#.
I've tried to use BitConverter.ToInt32 method, but my problem is what value should have the lats byte.
Can anybody suggest me how can I do it in different way?
I also need to convert 5 (or 6 or 7) bytes to signed long, is there any general rule how to do it?
Thanks in advance for any help.
As a last resort you could always shift+add yourself:
byte b1, b2, b3;
int r = b1 << 16 | b2 << 8 | b3;
Just swap b1/b2/b3 until you have the desired result.
On second thought, this will never produce negative values.
What result do you want when the msb >= 0x80 ?
Part 2, brute force sign extension:
private static int Bytes2Int(byte b1, byte b2, byte b3)
{
int r = 0;
byte b0 = 0xff;
if ((b1 & 0x80) != 0) r |= b0 << 24;
r |= b1 << 16;
r |= b2 << 8;
r |= b3;
return r;
}
I've tested this with:
byte[] bytes = BitConverter.GetBytes(p);
int r = Bytes2Int(bytes[2], bytes[1], bytes[0]);
Console.WriteLine("{0} == {1}", p, r);
for several p.
The last value should be 0 if it isn't set for a positive number, 256 for a negative.
To know what you should pass in, you can try converting it the other way:
var bytes = BitConverter.GetBytes(i);
int x = BitConverter.ToInt32(bytes, 0);
To add to the existing answers here, there's a bit of a gotcha in that Bitconverter.ToInt32() will throw an ArgumentException if the array is less than sizseof(int) (4) bytes in size;
Destination array is not long enough to copy all the items in the collection. Check array index and length.
Given an array less than sizeof(int) (4) bytes in size, you can compensate for left/right padding like so;
Right-pad
Results in positive Int32 numbers
int intByteSize = sizeof(int);
byte[] padded = new byte[intByteSize];
Array.Copy(sourceBytes, 0, padded, 0, sourceBytes.Length);
sourceBytes = padded;
Left-pad
Results in negative Int32 numbers, assuming non-zero value at byte index sourceBytes.Length - 1.
int intByteSize = sizeof(int);
byte[] padded = new byte[intByteSize];
Array.Copy(sourceBytes, 0, padded, intByteSize - sourceBytes.Length, sourceBytes.Length);
sourceBytes = padded;
Once padded, you can safely call int myValue = BitConverter.ToInt32(sourceBytes, 0);.
I want to convert an int to a byte[2] array using BCD.
The int in question will come from DateTime representing the Year and must be converted to two bytes.
Is there any pre-made function that does this or can you give me a simple way of doing this?
example:
int year = 2010
would output:
byte[2]{0x20, 0x10};
static byte[] Year2Bcd(int year) {
if (year < 0 || year > 9999) throw new ArgumentException();
int bcd = 0;
for (int digit = 0; digit < 4; ++digit) {
int nibble = year % 10;
bcd |= nibble << (digit * 4);
year /= 10;
}
return new byte[] { (byte)((bcd >> 8) & 0xff), (byte)(bcd & 0xff) };
}
Beware that you asked for a big-endian result, that's a bit unusual.
Use this method.
public static byte[] ToBcd(int value){
if(value<0 || value>99999999)
throw new ArgumentOutOfRangeException("value");
byte[] ret=new byte[4];
for(int i=0;i<4;i++){
ret[i]=(byte)(value%10);
value/=10;
ret[i]|=(byte)((value%10)<<4);
value/=10;
}
return ret;
}
This is essentially how it works.
If the value is less than 0 or greater than 99999999, the value won't fit in four bytes. More formally, if the value is less than 0 or is 10^(n*2) or greater, where n is the number of bytes, the value won't fit in n bytes.
For each byte:
Set that byte to the remainder of the value-divided-by-10 to the byte. (This will place the last digit in the low nibble [half-byte] of the current byte.)
Divide the value by 10.
Add 16 times the remainder of the value-divided-by-10 to the byte. (This will place the now-last digit in the high nibble of the current byte.)
Divide the value by 10.
(One optimization is to set every byte to 0 beforehand -- which is implicitly done by .NET when it allocates a new array -- and to stop iterating when the value reaches 0. This latter optimization is not done in the code above, for simplicity. Also, if available, some compilers or assemblers offer a divide/remainder routine that allows retrieving the quotient and remainder in one division step, an optimization which is not usually necessary though.)
Here's a terrible brute-force version. I'm sure there's a better way than this, but it ought to work anyway.
int digitOne = year / 1000;
int digitTwo = (year - digitOne * 1000) / 100;
int digitThree = (year - digitOne * 1000 - digitTwo * 100) / 10;
int digitFour = year - digitOne * 1000 - digitTwo * 100 - digitThree * 10;
byte[] bcdYear = new byte[] { digitOne << 4 | digitTwo, digitThree << 4 | digitFour };
The sad part about it is that fast binary to BCD conversions are built into the x86 microprocessor architecture, if you could get at them!
Here is a slightly cleaner version then Jeffrey's
static byte[] IntToBCD(int input)
{
if (input > 9999 || input < 0)
throw new ArgumentOutOfRangeException("input");
int thousands = input / 1000;
int hundreds = (input -= thousands * 1000) / 100;
int tens = (input -= hundreds * 100) / 10;
int ones = (input -= tens * 10);
byte[] bcd = new byte[] {
(byte)(thousands << 4 | hundreds),
(byte)(tens << 4 | ones)
};
return bcd;
}
maybe a simple parse function containing this loop
i=0;
while (id>0)
{
twodigits=id%100; //need 2 digits per byte
arr[i]=twodigits%10 + twodigits/10*16; //first digit on first 4 bits second digit shifted with 4 bits
id/=100;
i++;
}
More common solution
private IEnumerable<Byte> GetBytes(Decimal value)
{
Byte currentByte = 0;
Boolean odd = true;
while (value > 0)
{
if (odd)
currentByte = 0;
Decimal rest = value % 10;
value = (value-rest)/10;
currentByte |= (Byte)(odd ? (Byte)rest : (Byte)((Byte)rest << 4));
if(!odd)
yield return currentByte;
odd = !odd;
}
if(!odd)
yield return currentByte;
}
Same version as Peter O. but in VB.NET
Public Shared Function ToBcd(ByVal pValue As Integer) As Byte()
If pValue < 0 OrElse pValue > 99999999 Then Throw New ArgumentOutOfRangeException("value")
Dim ret As Byte() = New Byte(3) {} 'All bytes are init with 0's
For i As Integer = 0 To 3
ret(i) = CByte(pValue Mod 10)
pValue = Math.Floor(pValue / 10.0)
ret(i) = ret(i) Or CByte((pValue Mod 10) << 4)
pValue = Math.Floor(pValue / 10.0)
If pValue = 0 Then Exit For
Next
Return ret
End Function
The trick here is to be aware that simply using pValue /= 10 will round the value so if for instance the argument is "16", the first part of the byte will be correct, but the result of the division will be 2 (as 1.6 will be rounded up). Therefore I use the Math.Floor method.
I made a generic routine posted at IntToByteArray that you could use like:
var yearInBytes = ConvertBigIntToBcd(2010, 2);
static byte[] IntToBCD(int input) {
byte[] bcd = new byte[] {
(byte)(input>> 8),
(byte)(input& 0x00FF)
};
return bcd;
}