Hex to decimal in C#
using System.Globalization;
using System.Numerics;
Console.WriteLine(int.Parse("FFFFFFFF", NumberStyles.HexNumber)); // -1
Console.WriteLine(uint.Parse("FFFFFFFF", NumberStyles.HexNumber)); // 4294967295
Console.WriteLine(Convert.ToInt32("0xFF", 16)); // 255
Console.WriteLine(int.TryParse("0xFF", NumberStyles.HexNumber, null, out _)); // False
Console.WriteLine(0xFFFFFFFF); // 4294967295
Console.WriteLine(unchecked((int)0xFFFFFFFF)); // -1
Console.WriteLine(BigInteger.Parse("FF", NumberStyles.HexNumber)); // -1
Console.WriteLine(BigInteger.Parse("0FF", NumberStyles.HexNumber)); // 255
int.Parse(s, NumberStyles.HexNumber)reads the digits as a bit pattern of the type's width: "FFFFFFFF" is -1 forintand 4294967295 foruint. Leading zeros do not count, but a ninth significant digit does: OverflowException: "Value was either too large or too small for an Int32.". It allows spaces around the digits, and no sign and no prefix: "0xFF" gives FormatException: "The input string '0xFF' was not in a correct format." on .NET 8 and .NET 10 alike. Strip the0xfirst, or use Convert.Convert.ToInt32(s, 16)accepts a0xor0Xprefix, but no spaces (FormatException: "Could not find any recognizable digits.") and no minus sign (ArgumentException: "String cannot contain a minus sign if the base is not 10."). Too many digits gives OverflowException: "Value was either too large or too small for a UInt32.", naming UInt32 even for ToInt32.BigInteger.Parse(s, NumberStyles.HexNumber)has no width, so the first digit carries the sign: 8 to F make the value negative. "FF" is -1 and "0FF" is 255. Prepend a "0" to hex you know is positive.
Two's complement: why FFFFFFFF is -1
C# stores sbyte, short, int and long in two's complement: the top bit counts as minus 2n-1 instead of plus. So the 32 bits FFFFFFFF are -1 as an int and 4294967295 as a uint, and 80000000 is int.MinValue. To negate a value, invert the bits and add 1: 1 is 00000001, -1 is FFFFFFFF, -255 is FFFFFF01.
A cast between types of the same width keeps the bits and changes their meaning; a cast to a narrower type keeps the low bits. Constants need unchecked: (int)0xFFFFFFFF does not compile (error CS0221), unchecked((int)0xFFFFFFFF) is -1. Pick a width above to see both readings of the same bits.
C# integer literals and their type
An integer literal without a suffix gets the first of int, uint, long, ulong that can hold it. With u it is uint or ulong, with L long or ulong, and with UL always ulong. Hex and binary follow the same rule, which is why 0xFFFFFFFF is a uint and int x = 0xFFFFFFFF; does not compile:
Console.WriteLine((0x7FFFFFFF).GetType().Name); // Int32
Console.WriteLine((0xFFFFFFFF).GetType().Name); // UInt32
Console.WriteLine((0x1_0000_0000).GetType().Name); // Int64
Console.WriteLine((0xFFFF_FFFF_FFFF_FFFF).GetType().Name); // UInt64
Console.WriteLine((0xFFu).GetType().Name); // UInt32
Console.WriteLine((0xFFL).GetType().Name); // Int64
Console.WriteLine((-2147483648).GetType().Name); // Int32
Console.WriteLine((-2147483649).GetType().Name); // Int64
Console.WriteLine(010); // 10
- Prefixes:
0xor0Xfor hex,0bor0Bfor binary (C# 7). C# has no octal literal:010is ten. - Digit separators:
_can go between any digits, and more than one in a row:1_000_000,0b1010_1010. Right after0xor0bis fine too (0x_FF, C# 7.2), but not at the end:0xFF_is error CS1013, "Invalid number". - Suffixes:
u,l,ulorluin any case. A lowercaselfirst draws warning CS0078 because it looks like a 1; writeL. - Negative literals: the minus is an operator applied to the literal, so
-2147483648is an int only thanks to a special rule,-2147483649is a long, and-18446744073709551615is error CS0023, sinceulonghas no minus. Pastulong.MaxValuea literal is error CS1021, "Integral constant is too large"; useBigInteger.Parse.
FAQ
How do I convert hex to decimal in C#?
Convert.ToInt32(hex, 16), or int.Parse(hex, NumberStyles.HexNumber). Use long, ulong or BigInteger for more than 8 hex digits.
Why does int.Parse("FFFFFFFF", NumberStyles.HexNumber) return -1?
Hex parsing reads the digits as the 32 bits of an int, and FFFFFFFF with the top bit set is -1 in two's complement. uint.Parse gives 4294967295 for the same text.
Does int.Parse accept the 0x prefix?
No. With NumberStyles.HexNumber, "0xFF" throws a FormatException on both .NET 8 and .NET 10. Convert.ToInt32(s, 16) accepts it.
Why is BigInteger.Parse("FF", NumberStyles.HexNumber) negative?
BigInteger reads hex as two's complement with the first digit as the sign, so FF is -1. Add a leading zero: "0FF" is 255.
What type is 0xFFFFFFFF in C#?
uint: the first of int, uint, long and ulong that can hold 4294967295. To get -1 as an int, write unchecked((int)0xFFFFFFFF).