Int and UInt in C#

By That Developer Guy
(Learn, Build, and Unlock Your Inner Dev)


What Are Int and UInt?

The int and uint types are the most commonly used integer types in C#. They store 32-bit (4-byte) whole numbers, providing a good balance between range and memory usage. This makes them the default choice for most integer values in C# programming.

The key difference between them:

  • int - Signed (can hold positive and negative numbers)
  • uint - Unsigned (positive numbers only)
Data Type Range Memory Struct
int -2,147,483,648 to 2,147,483,647 4 bytes (32 bits) System.Int32
uint 0 to 4,294,967,295 4 bytes (32 bits) System.UInt32

int and uint

Important: int is by far the most commonly used integer type in C#. When you write a number literal like 42, the compiler treats it as an int by default.


When to Use Int and UInt

Int (Most Common)

  • Default choice for counting, indexing, and general integer values
  • Loop counters and array indices
  • User ages, scores, quantities
  • Calculations involving positive and negative numbers
  • Database IDs and primary keys
  • Year values, days, hours, minutes
  • Any integer value where you might need negatives

UInt (Less Common)

  • When you're certain values will never be negative
  • Working with binary data or bitwise operations
  • Interoperating with APIs that require unsigned integers
  • When you need the extra positive range (up to 4.2 billion)
  • File sizes and memory addresses
  • Color values and pixel data

Best Practice: Use int unless you have a specific reason to use uint. Most C# APIs and methods expect int, and using uint can sometimes require extra casting.


Basic Syntax

Declaration and Initialization

// Using int keyword (recommended)
int count = 10;
int temperature = -5;
int maxStudents = 100;

// Using System.Int32 struct
System.Int32 number = 42;

// Unsigned integer
uint population = 7900000000;
uint distance = 384400;  // kilometers to moon

// Using System.UInt32 struct
System.UInt32 largeValue = 3000000000;

Using 'int' vs 'Int32'

The lowercase int is an alias for System.Int32. They are identical, but int is the standard, preferred way to declare integer variables.

using System;

namespace GetCoding
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 0;       // Recommended - simple and clean
            Int32 b = 0;     // Works in .NET 8+, needs 'using System;' in earlier versions
            
            uint c = 0;      // Recommended
            UInt32 d = 0;    // Works in .NET 8+, needs 'using System;' in earlier versions
        }
    }
}

Best Practice: Always use lowercase int and uint for consistency with C# conventions.


Using var with Int and UInt

When using the var keyword, numeric literals default to int, so be careful when working with uint.

int a = 0;            // Explicitly int
var b = 0;            // Defaults to int - no casting needed
var c = (int)0;       // Explicitly int (casting unnecessary here)

uint d = 0;           // Explicitly uint
var e = (uint)0;      // Must cast to make it uint
var f = new uint();   // This is uint with default value of 0

// Examples
var score = 100;      // This is int
var population = 3000000000;  // This is int, but causes error! Value too large
var population = 3000000000u; // Use 'u' suffix for uint literal

Pro Tip: Add a u or U suffix to numeric literals to make them uint:

uint bigNumber = 3000000000u;  // u suffix makes it uint
var alsoBig = 3000000000U;     // U suffix also works

Properties: MinValue and MaxValue

Every integer type in C# has MinValue and MaxValue properties that define the boundaries of values the type can hold.

using System;

class Program
{
    static void Main(string[] args)
    {
        // Int properties
        int intMin = int.MinValue;      // -2,147,483,648
        int intMax = int.MaxValue;      // 2,147,483,647
        
        // UInt properties
        uint uintMin = uint.MinValue;   // 0
        uint uintMax = uint.MaxValue;   // 4,294,967,295
        
        // Display the values
        Console.WriteLine($"int range: {intMin:N0} to {intMax:N0}");
        Console.WriteLine($"uint range: {uintMin:N0} to {uintMax:N0}");
        
        Console.ReadKey();
    }
}

Output:

int range: -2,147,483,648 to 2,147,483,647
uint range: 0 to 4,294,967,295

Practical Uses of MinValue and MaxValue

// Validation
public bool IsValidYear(int year)
{
    return year >= 1900 && year <= DateTime.Now.Year;
}

// Initialize to extreme values
int lowestScore = int.MaxValue;  // Start with highest, find lowest
int highestScore = int.MinValue; // Start with lowest, find highest

// Range checking before conversion
long bigNumber = 5000000000L;
if (bigNumber >= int.MinValue && bigNumber <= int.MaxValue)
{
    int converted = (int)bigNumber;
}
else
{
    Console.WriteLine("Value outside int range!");
}

// Finding min/max in a loop
int[] scores = { 85, 92, 78, 95, 88 };
int min = int.MaxValue;
int max = int.MinValue;

foreach (int score in scores)
{
    if (score < min) min = score;
    if (score > max) max = score;
}

Nullable Int

By default, value types like int and uint cannot be null. However, you can make them nullable using the ? syntax.

int regularInt = 10;      // Cannot be null
int? nullableInt = null;  // Can be null

// Checking for null
if (nullableInt.HasValue)
{
    Console.WriteLine($"Value is: {nullableInt.Value}");
}
else
{
    Console.WriteLine("No value assigned");
}

// Using null-coalescing operator
int result = nullableInt ?? 0;  // Use 0 if null

// Common in database operations
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? StockQuantity { get; set; }  // Null means unknown/not tracked
}

Overflow Behavior

By default, arithmetic operations on int and uint do not check for overflow. When a value exceeds the type's range, it wraps around.

// Int overflow
int maxInt = int.MaxValue;      // 2,147,483,647
int overflow = maxInt + 1;       // -2,147,483,648 (wraps to minimum)

// UInt overflow
uint maxUInt = uint.MaxValue;    // 4,294,967,295
uint uintOverflow = maxUInt + 1; // 0 (wraps around)

Checked Context

Enable overflow checking using the checked keyword to throw exceptions instead of wrapping:

try
{
    checked
    {
        int maxInt = int.MaxValue;
        int result = maxInt + 1;  // Throws OverflowException
    }
}
catch (OverflowException ex)
{
    Console.WriteLine("Overflow detected! Value too large.");
}

// Check a specific operation
int result = checked(maxInt + 1);

// Check an entire block
checked
{
    int a = int.MaxValue;
    int b = 100;
    int c = a + b;  // Throws OverflowException
}

Unchecked Context

You can explicitly disable overflow checking (though it's the default):

unchecked
{
    int maxInt = int.MaxValue;
    int result = maxInt + 1;  // Wraps around, no exception
}

See Also: Overflow Exception for comprehensive coverage of overflow handling.


Type Conversion

Implicit Conversion (Safe)

int and uint can be implicitly converted to larger types:

int myInt = 42;

// Implicit conversions (safe, no data loss)
long myLong = myInt;
float myFloat = myInt;
double myDouble = myInt;
decimal myDecimal = myInt;

// UInt to larger unsigned types
uint myUInt = 100;
ulong myULong = myUInt;

Explicit Conversion (Casting Required)

Converting from larger types or between signed/unsigned requires explicit casting:

long bigNumber = 5000000000L;
int smallNumber = (int)bigNumber;  // Data loss! Wraps around

// Safer approach
if (bigNumber >= int.MinValue && bigNumber <= int.MaxValue)
{
    int safeConversion = (int)bigNumber;
}
else
{
    Console.WriteLine("Value out of int range!");
}

// Converting between signed and unsigned
int signedValue = -10;
uint unsignedValue = (uint)signedValue;  // Dangerous! Results in large positive number

uint largeUInt = 3000000000;
int signedFromUInt = (int)largeUInt;  // Overflow! Becomes negative

Using Convert and Parse

// String to int
string numberText = "123";
int number = int.Parse(numberText);

// Safe parsing with TryParse (recommended)
if (int.TryParse("456", out int result))
{
    Console.WriteLine($"Converted: {result}");
}
else
{
    Console.WriteLine("Invalid number format");
}

// Using Convert class
int converted = Convert.ToInt32("789");
uint uintConverted = Convert.ToUInt32("1000");

// Handling different number formats
int hexNumber = Convert.ToInt32("FF", 16);     // Hexadecimal
int binaryNumber = Convert.ToInt32("1010", 2); // Binary

Practical Examples

Example 1: Loop Counters

// Most common use of int
for (int i = 0; i < 10; i++)
{
    Console.WriteLine($"Iteration: {i}");
}

// Countdown
for (int countdown = 10; countdown > 0; countdown--)
{
    Console.WriteLine(countdown);
}
Console.WriteLine("Blast off!");

Example 2: Array Indexing

string[] names = { "Alice", "Bob", "Charlie", "David" };

for (int index = 0; index < names.Length; index++)
{
    Console.WriteLine($"{index + 1}. {names[index]}");
}

Example 3: Age Calculation

public class Person
{
    public string Name { get; set; }
    public int BirthYear { get; set; }
    
    public int GetAge()
    {
        int currentYear = DateTime.Now.Year;
        return currentYear - BirthYear;
    }
}

// Usage
Person person = new Person 
{ 
    Name = "John", 
    BirthYear = 1990 
};

Console.WriteLine($"{person.Name} is {person.GetAge()} years old");

Example 4: Score Tracking

public class Game
{
    private int _score;
    private int _highScore;
    
    public int Score 
    { 
        get { return _score; }
        private set
        {
            _score = value;
            if (_score > _highScore)
            {
                _highScore = _score;
            }
        }
    }
    
    public int HighScore { get { return _highScore; } }
    
    public void AddPoints(int points)
    {
        if (points > 0)
        {
            Score += points;
            Console.WriteLine($"Score: {Score} (High: {HighScore})");
        }
    }
}

Example 5: File Size (UInt)

public class FileInfo
{
    public string FileName { get; set; }
    public uint SizeInBytes { get; set; }
    
    public string GetReadableSize()
    {
        if (SizeInBytes < 1024)
            return $"{SizeInBytes} bytes";
        else if (SizeInBytes < 1024 * 1024)
            return $"{SizeInBytes / 1024.0:F2} KB";
        else if (SizeInBytes < 1024 * 1024 * 1024)
            return $"{SizeInBytes / (1024.0 * 1024):F2} MB";
        else
            return $"{SizeInBytes / (1024.0 * 1024 * 1024):F2} GB";
    }
}

Common Mistakes to Avoid

Mistake 1: Integer Division

int a = 5;
int b = 2;
int result = a / b;        // result = 2, not 2.5!

// To get decimal result, cast to double
double decimalResult = (double)a / b;  // result = 2.5

Mistake 2: Overflow Without Checking

int count = int.MaxValue;
count++;  // Wraps to int.MinValue!

// Better approach
if (count < int.MaxValue)
{
    count++;
}
else
{
    Console.WriteLine("Cannot increment, at maximum value");
}

Mistake 3: Using UInt Unnecessarily

// Bad - creates casting issues
public uint GetLength()  
{
    return (uint)myArray.Length;  // Length is int, requires cast
}

// Good - use int
public int GetLength()
{
    return myArray.Length;  // No casting needed
}

Mistake 4: Negative UInt Values

int temperature = -5;
uint unsignedTemp = (uint)temperature;  // Becomes 4,294,967,291!

// This is almost never what you want
Console.WriteLine(unsignedTemp);  // Prints huge positive number

Performance Considerations

Int vs Long

// Use int when possible - it's faster and uses less memory
int count = 0;        // Preferred for most cases
long bigCount = 0;    // Only when you need the range

// Int is faster in loops
for (int i = 0; i < 1000000; i++)  // Faster
{
    // Do work
}

for (long i = 0; i < 1000000; i++)  // Slower
{
    // Do work
}

Bitwise Operations

// Int is ideal for bit manipulation
int flags = 0;
const int FLAG_READ = 1;      // 0001
const int FLAG_WRITE = 2;     // 0010
const int FLAG_EXECUTE = 4;   // 0100

// Set flags
flags |= FLAG_READ | FLAG_WRITE;

// Check flags
bool canRead = (flags & FLAG_READ) != 0;
bool canWrite = (flags & FLAG_WRITE) != 0;

Key Takeaways

  • int is the default choice for integer values in C# (use it 95% of the time)
  • uint is for positive-only values when you need the extra range
  • Both store 32 bits (4 bytes) of data
  • Use lowercase int and uint keywords (not Int32/UInt32)
  • Be aware of integer division (5 / 2 = 2, not 2.5)
  • Watch for overflow when doing arithmetic
  • Use int.MaxValue and int.MinValue for boundary checking
  • int? makes integers nullable for database operations

Next Steps

Explore related integer types and concepts: