First of all you should check the type of your value. You can do it by calling obj.GetType() method (either in your code directly or in Immediate window).
If it is int then you can do:
uint u = (uint) (int) obj;
Please note that it differs from your cast because it casts to int and then converts to uint while you were trying to cast to uint. int cannot be cast to uint and that is why you get the InvalidCastException. int can be only converted to uint. It is confusing that both conversion and cast operators look same in code: u = (uint) x.
Easier thing you can do is calling a specific method from Convert class:
uint u = Convert.ToUInt32(x);
Answer from Snowbear on Stack OverflowFirst of all you should check the type of your value. You can do it by calling obj.GetType() method (either in your code directly or in Immediate window).
If it is int then you can do:
uint u = (uint) (int) obj;
Please note that it differs from your cast because it casts to int and then converts to uint while you were trying to cast to uint. int cannot be cast to uint and that is why you get the InvalidCastException. int can be only converted to uint. It is confusing that both conversion and cast operators look same in code: u = (uint) x.
Easier thing you can do is calling a specific method from Convert class:
uint u = Convert.ToUInt32(x);
The problem is that int is stored as object. Int derives from object but uint doesn't derive from int so you can't cast int stored as object to uint. First you have to cast it to int and then to uint because that cast is valid. Try it yourself:
object o = 5;//this is constant that represents int, constant for uint would be 5u
uint i = (uint)o;//throws exception
But this works:
object o = 5;
int i = (int)o;
uint j = (uint)i;
or
object o = 5;
uint i = (uint)(int)o; //No matter how this looks awkward
To convert one type to another, use uint(x) or int(x). The rules are basically the same as in C, where the first bit of the uint becomes the sign.
For example:
if (int(a - b) < c) doSomething();
is likely what you want, as the numbers will be subtracted, then converted.
The type(x) syntax is used for all kinds of casting, such as truncating a number (uint8(someUint)), converting to and from odd types (bytes32(someUint)), or even casting a given address to a specific contract type (someContract(someAddress)).
You can cast from uint to int by just doing int(a-b) but be careful. The int type in solidity uses the two's complement system, so if you accidental cast a very large uint to an int, or a negative int to a uint, you may get unexpected results.
The values where this would happen are extremely large (numbers greater than 2^255, or about 10^77), so you don't usually need to worry, but remember that uint(5-8) is 115792089237316195423570985008687907853269984665640564039457584007913129639933
Negative numbers (like -24) are represented as a binary complement, see
en.wikipedia.org/wiki/Two's_complement
for details. In your case
24 = 00000000000000000000000000011000
~24 = 11111111111111111111111111100111
~24 + 1 = 11111111111111111111111111101000 =
= 4294967272
When casting int to uint be careful, since -24 is beyond uint range (which [0..uint.MaxValue]) you can have OverflowException being thrown. A safier implementation is
int x = -24;
uint y = unchecked((uint) x); // do not throw OverflowException exception
There are few ways to convert int to uint
int x;
Technique #1
uint y = Convert.ToUInt32(x);
Technique #2
uint y = checked((uint) x);
Technique #3
uint y = unchecked((uint) x);
Technique #4
uint y = (uint) x;
Given:
uint n = 3;
int i = checked((int)n); //throws OverflowException if n > Int32.MaxValue
int i = unchecked((int)n); //converts the bits only
//i will be negative if n > Int32.MaxValue
int i = (int)n; //same behavior as unchecked
or
int i = Convert.ToInt32(n); //same behavior as checked
--EDIT
Included info as mentioned by Kenan E. K.
Assuming you want to simply lift the 32bits from one type and dump them as-is into the other type:
uint asUint = unchecked((uint)myInt);
int asInt = unchecked((int)myUint);
The destination type will blindly pick the 32 bits and reinterpret them.
Conversely if you're more interested in keeping the decimal/numerical values within the range of the destination type itself:
uint asUint = checked((uint)myInt);
int asInt = checked((int)myUint);
In this case, you'll get overflow exceptions if:
- casting a negative int (eg: -1) to an uint
- casting a positive uint between 2,147,483,648 and 4,294,967,295 to an int
In our case, we wanted the unchecked solution to preserve the 32bits as-is, so here are some examples:
Examples
int => uint
int....: 0000000000 (00-00-00-00)
asUint.: 0000000000 (00-00-00-00)
------------------------------
int....: 0000000001 (01-00-00-00)
asUint.: 0000000001 (01-00-00-00)
------------------------------
int....: -0000000001 (FF-FF-FF-FF)
asUint.: 4294967295 (FF-FF-FF-FF)
------------------------------
int....: 2147483647 (FF-FF-FF-7F)
asUint.: 2147483647 (FF-FF-FF-7F)
------------------------------
int....: -2147483648 (00-00-00-80)
asUint.: 2147483648 (00-00-00-80)
uint => int
uint...: 0000000000 (00-00-00-00)
asInt..: 0000000000 (00-00-00-00)
------------------------------
uint...: 0000000001 (01-00-00-00)
asInt..: 0000000001 (01-00-00-00)
------------------------------
uint...: 2147483647 (FF-FF-FF-7F)
asInt..: 2147483647 (FF-FF-FF-7F)
------------------------------
uint...: 4294967295 (FF-FF-FF-FF)
asInt..: -0000000001 (FF-FF-FF-FF)
------------------------------
Code
int[] testInts = { 0, 1, -1, int.MaxValue, int.MinValue };
uint[] testUints = { uint.MinValue, 1, uint.MaxValue / 2, uint.MaxValue };
foreach (var Int in testInts)
{
uint asUint = unchecked((uint)Int);
Console.WriteLine("int....: {0:D10} ({1})", Int, BitConverter.ToString(BitConverter.GetBytes(Int)));
Console.WriteLine("asUint.: {0:D10} ({1})", asUint, BitConverter.ToString(BitConverter.GetBytes(asUint)));
Console.WriteLine(new string('-',30));
}
Console.WriteLine(new string('=', 30));
foreach (var Uint in testUints)
{
int asInt = unchecked((int)Uint);
Console.WriteLine("uint...: {0:D10} ({1})", Uint, BitConverter.ToString(BitConverter.GetBytes(Uint)));
Console.WriteLine("asInt..: {0:D10} ({1})", asInt, BitConverter.ToString(BitConverter.GetBytes(asInt)));
Console.WriteLine(new string('-', 30));
}
You can convert an int to an unsigned int. The conversion is valid and well-defined.
Since the value is negative, UINT_MAX + 1 is added to it so that the value is a valid unsigned quantity. (Technically, 2N is added to it, where N is the number of bits used to represent the unsigned type.)
In this case, since int on your platform has a width of 32 bits, 62 is subtracted from 232, yielding 4,294,967,234.
Edit: As has been noted in the other answers, the standard actually guarantees that "the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type)". So even if your platform did not store signed ints as two's complement, the behavior would be the same.
Apparently your signed integer -62 is stored in two's complement (Wikipedia) on your platform:
62 as a 32-bit integer written in binary is
0000 0000 0000 0000 0000 0000 0011 1110
To compute the two's complement (for storing -62), first invert all the bits
1111 1111 1111 1111 1111 1111 1100 0001
then add one
1111 1111 1111 1111 1111 1111 1100 0010
And if you interpret this as an unsigned 32-bit integer (as your computer will do if you cast it), you'll end up with 4294967234 :-)