Reputation: 97
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?
Upvotes: 8
Views: 5050
Reputation: 12171
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.
Upvotes: 5
Reputation: 30464
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);
Upvotes: 0
Reputation: 186698
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
.
Upvotes: 5
Reputation: 49189
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
.
Upvotes: 0
Reputation: 11
try this
uint pesoparz = (Convert.ToUInt16(values[0]));
Int32 pesotot = Convert.ToInt32(pesoparz *65536 + Convert.ToUInt32(values[1]));
Seems you are reaching the limit
Upvotes: 0
Reputation: 109577
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]));
Upvotes: 1