Convert a Short[2] to Int32 in C#
Asked Answered
A

6

8

I have a short array in c# and I need to convert two elements in an Int32. The code I wrote is the following

uint pesoparz = (Convert.ToUInt16(values[0]));
Int32 pesotot = Convert.ToInt32(pesoparz *65536 + Convert.ToUInt16(values[1]));

where values[] is the short array and pesotot is the Int32 that I would like to obtain. It works but unfortunately when the value[1] exceeds 2^15, I get the system overflow exception.

Why does the exception occur?

Apophyge answered 11/1, 2017 at 14:32 Comment(5)
use uncheck to get around it.Claude
@Claude Right, that superficially fixes the software, but the calculation is still not as desired.Londalondon
The sign extension is probably causing the error. Try following : uint pesoparz = ((values[1] & 0xFFFF) << 16) | (values[0] & 0xFFFF);Intubate
You can always use listByte.AddRange(BitConverter.GetBytes(shortArr[0])); listByte.AddRange(BitConverter.GetBytes(shortArr[1])); Int32 result = BitConverter.ToInt32(listByte.ToArray());Irradiance
@Claude I suggest you convert your comment to an answer.Londalondon
R
5

You're looking for unchecked which switches off IntegerOverflow:

  short left = -123;
  short right = -456;

  int result = unchecked(BitConverter.IsLittleEndian 
    ? (UInt16)left << 16 | (UInt16)right 
    : (UInt16)right << 16 | (UInt16)left);

You may want to use BitConverter.IsLittleEndian to detect the order in which short parts should be combined into int.

Reinold answered 11/1, 2017 at 14:37 Comment(0)
M
5

You can use bitwise operators:

short[] parts = new short[2];
parts[0] = 1;
parts[1] = 2;

uint result = 0;

result = (ushort)parts[0] << 16 | (ushort)parts[1];

The result will be 0x00010002 in hex or 65538 in decimal.

Mientao answered 11/1, 2017 at 14:44 Comment(0)
P
1

It's best to use shift and or for this, and use unchecked to prevent an overflow error:

int result = unchecked((int)(((uint)values[0] << 16) | values[1]));
Perreault answered 11/1, 2017 at 14:37 Comment(0)
M
0

try this

uint pesoparz = (Convert.ToUInt16(values[0]));
Int32 pesotot = Convert.ToInt32(pesoparz *65536 + Convert.ToUInt32(values[1]));

Seems you are reaching the limit

Marten answered 11/1, 2017 at 14:37 Comment(0)
T
0
short[] arr = new short[] { 512, -32767 };

int ival = ((int)arr[0] * 65536) + ((int)arr[1] & 0xffff);
// also:
// ival = ((int)arr[0] << 16) | ((int)arr[1] & 0xffff); 
Console.WriteLine(ival);

This gives a correct result of 33587201. The trick, if there is one, is to use casting to get the shorts into ints and then to mask off the parts you don't want (in this case, the sign extension). This neither requires Convert nor unchecked.

Theorem answered 11/1, 2017 at 14:40 Comment(0)
M
0

Are you sure each value of your values array fits in an Int16?

If not, then even if you uncheck, the result is not what you want. First you'll have to decide what to do if values[0] or values1 is larger than fits in an Int16.

Your decision depends on what the values mean. Does values[0] represent the Highest 16 bits of your resulting Int32 and values[0] the lowest 16 bits?

In that case you should throw an ArgumentException if either values[0] or values1 is more than Int16.MaxValue. After that your code is easy:

if (values[0] > Int16.MaxValue || values[1] > Int16.MaxValue)
    throw new ArgumentException("values should fit in two bytes");
Int32 result = values[0] << 0x10000 + values[1];
return result;

It could also mean that it is allowed that both values are more than 0x10000, You should think of yourself what you want as a result if the numbers are too big.

By the way, if your values each represent one half of an Int32, consider switching the meaning of values[0] and values1. Almost always the least significant bits (LSB) are in [0], while the most significant bits (MSB) are in 1. If you follow this convention, you don't have to write these converters yourself, you can use the BitConverter class

Int32 original = 0x12345678;
byte[] bytes = BitConverter.GetBytes(original);
foreach (var b in bytes)
    Console.WriteLine(b.ToString("02X"); // write in two digit hex format
// will write lines with 78 56 34 12
Int16[] Values = new Int16[]
{
    BitConverter.ToInt16(bytes),     // LSB
    BitConverter.ToInt16(bytes, 2),  // MSB
};
Int32 result = (Int32)values[0] + (Int32)values[1] << 0x10000;
Debug.Assert(original == result);
Maragretmarala answered 11/1, 2017 at 14:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.