I have this expression
long balance = (long)answer.Find(DppGlobals.TAG_TI_BALANCE).Get_QWORD();
which raises exception that there was overflow. The value on the right hand side is of unsigned type and has value: 18446744073708240732.
How to avoid this exception, use unchecked
?
PS equivalent C++ implementation returned balance = -1310984, I need same value here too.
Why is there such an exception?
By using unchecked indeed now also on C# side I get -1310984. Can someone advice, am I losing data somehow?
Given the comments, it sounds like you do just need to use unchecked arithmetic - but you should be concerned about the use of ulong
in your API. If your aim is to just propagate 8 bytes of data, and interpret it as either an unsigned integer or a signed integer depending on context, then you're fine - so long as nothing performs arithmetic on it in the "wrong" form.
It's important to understand why this happens though, and it's much easier to explain that with small numbers. I'll use byte
and sbyte
as an example. The range of byte
is 0 to 255 inclusive. The range of sbyte
is -128 to 127 inclusive. Both can store 256 different values. No problem.
Now, using unchecked conversions, it's fine to say:
byte a = GetByteFromSomewhere();
sbyte b = (sbyte) a;
StoreSByteSomewhere(b);
...
sbyte b = GetSByteFromStorage();
byte a = (byte) b;
If that's all you're doing, that's fine. A byte
value of -1 will become an sbyte
value of 255 and vice versa - basically it's just interpreting the same bit pattern in different ways.
But if you're performing other operations on the value when it's being handled as the "wrong" type, then you could get unexpected answers. For example, consider "dividing by 3". If you divide -9 by 3, you get -3, right? Whereas if you have:
byte original = -9;
sbyte converted = (sbyte) original;
sbyte divided = converted / 3;
byte result = (byte) divided;
... then you end up with a result of -2 instead of -3, due to the way the arithmetic worked.
Now that's all for unchecked conversions. When you have a checked conversion, it doesn't just interpret the bits - it treats the value as a number instead. So for example:
// In a checked context...
byte a = 128;
sbyte b = (sbyte) a; // Bang! Exception
That's because 128 (as a number) is outside the range of sbyte
. This is what's happening in your case - the number 18446744073708240732 is outside the range of long
, so you're getting an exception. The checked conversion is treating it as a number which can be range-checked, rather than an unchecked conversion just reinterpreting the bits as a long
(which leads to the negative number you want).
See more on this question at Stackoverflow