Coming Soon

This lesson is currently being developed

Signed integers

Understand signed integer types and their ranges.

Fundamental Data Types
Chapter
Beginner
Difficulty
35min
Estimated Time

What to Expect

Comprehensive explanations with practical examples

Interactive coding exercises to practice concepts

Knowledge quiz to test your understanding

Step-by-step guidance for beginners

Development Status

In Progress

Content is being carefully crafted to provide the best learning experience

Preview

Early Preview Content

This content is still being developed and may change before publication.

4.4 — Signed integers

In this lesson, you'll learn about signed integer types in C++, their ranges, and how to use them effectively to store positive and negative whole numbers.

What are signed integers?

Signed integers are data types that can store both positive and negative whole numbers, as well as zero. The word "signed" indicates that these types can represent numbers with a sign (+ or -).

Think of signed integers like a thermometer that can show both temperatures above and below zero - they can handle both positive and negative values.

C++ signed integer types

C++ provides several signed integer types with different sizes and ranges:

#include <iostream>
#include <climits>  // For integer limit constants

int main()
{
    std::cout << "Signed Integer Types and Ranges:\n\n";
    
    // signed char (usually 8 bits)
    std::cout << "signed char:\n";
    std::cout << "  Size: " << sizeof(signed char) << " byte(s)\n";
    std::cout << "  Range: " << static_cast<int>(SCHAR_MIN) 
              << " to " << static_cast<int>(SCHAR_MAX) << "\n\n";
    
    // short (usually 16 bits)
    std::cout << "short:\n";
    std::cout << "  Size: " << sizeof(short) << " byte(s)\n";
    std::cout << "  Range: " << SHRT_MIN << " to " << SHRT_MAX << "\n\n";
    
    // int (usually 32 bits)
    std::cout << "int:\n";
    std::cout << "  Size: " << sizeof(int) << " byte(s)\n";
    std::cout << "  Range: " << INT_MIN << " to " << INT_MAX << "\n\n";
    
    // long (at least 32 bits)
    std::cout << "long:\n";
    std::cout << "  Size: " << sizeof(long) << " byte(s)\n";
    std::cout << "  Range: " << LONG_MIN << " to " << LONG_MAX << "\n\n";
    
    // long long (at least 64 bits)
    std::cout << "long long:\n";
    std::cout << "  Size: " << sizeof(long long) << " byte(s)\n";
    std::cout << "  Range: " << LLONG_MIN << " to " << LLONG_MAX << "\n";
    
    return 0;
}

Typical Output:

Signed Integer Types and Ranges:

signed char:
  Size: 1 byte(s)
  Range: -128 to 127

short:
  Size: 2 byte(s)
  Range: -32768 to 32767

int:
  Size: 4 byte(s)
  Range: -2147483648 to 2147483647

long:
  Size: 8 byte(s)
  Range: -9223372036854775808 to 9223372036854775807

long long:
  Size: 8 byte(s)
  Range: -9223372036854775808 to 9223372036854775807

Declaring and initializing signed integers

By default, integer types in C++ are signed (the signed keyword is optional):

#include <iostream>

int main()
{
    // These declarations are equivalent:
    int temperature1 = -15;        // int is signed by default
    signed int temperature2 = -15; // explicitly signed (same as above)
    
    // Various ways to declare signed integers
    signed char grade = -5;        // Very small range
    short altitude = -1500;        // Elevation below sea level
    int bankBalance = -2500;       // Negative bank balance
    long population = 8000000000L; // Large positive number
    long long distance = -9876543210987654LL; // Very large negative number
    
    // Display the values
    std::cout << "Signed integer values:\n";
    std::cout << "Grade adjustment: " << static_cast<int>(grade) << std::endl;
    std::cout << "Altitude: " << altitude << " feet\n";
    std::cout << "Bank balance: $" << bankBalance << std::endl;
    std::cout << "Population: " << population << std::endl;
    std::cout << "Distance: " << distance << " units\n";
    
    return 0;
}

Output:

Signed integer values:
Grade adjustment: -5
Altitude: -1500 feet
Bank balance: $-2500
Population: 8000000000
Distance: -9876543210987654 units

Understanding signed integer ranges

Signed integers use one bit to represent the sign, leaving fewer bits for the magnitude:

How signed integers work

#include <iostream>
#include <climits>

int main()
{
    std::cout << "Understanding signed integer ranges:\n\n";
    
    // For 8-bit signed char: 1 bit for sign, 7 bits for magnitude
    std::cout << "8-bit signed char (1 byte):\n";
    std::cout << "  Total values: 2^8 = " << (1 << 8) << std::endl;
    std::cout << "  Range: " << static_cast<int>(SCHAR_MIN) 
              << " to " << static_cast<int>(SCHAR_MAX) << std::endl;
    std::cout << "  Total range span: " 
              << (static_cast<int>(SCHAR_MAX) - static_cast<int>(SCHAR_MIN) + 1) << " values\n\n";
    
    // For 16-bit short: 1 bit for sign, 15 bits for magnitude  
    std::cout << "16-bit short (2 bytes):\n";
    std::cout << "  Total values: 2^16 = " << (1 << 16) << std::endl;
    std::cout << "  Range: " << SHRT_MIN << " to " << SHRT_MAX << std::endl;
    std::cout << "  Total range span: " << (static_cast<long long>(SHRT_MAX) - SHRT_MIN + 1) << " values\n\n";
    
    // For 32-bit int: 1 bit for sign, 31 bits for magnitude
    std::cout << "32-bit int (4 bytes):\n";
    std::cout << "  Total values: 2^32 = " << (1LL << 32) << std::endl;
    std::cout << "  Range: " << INT_MIN << " to " << INT_MAX << std::endl;
    std::cout << "  Positive values: 0 to " << INT_MAX << " (" << INT_MAX << " values)\n";
    std::cout << "  Negative values: " << INT_MIN << " to -1 (" << -static_cast<long long>(INT_MIN) << " values)\n";
    
    return 0;
}

Practical uses of signed integers

Temperature measurements

#include <iostream>

int main()
{
    // Signed integers are perfect for temperature
    int celsiusTemperatures[] = {-40, -10, 0, 15, 25, 35, 50};
    int numTemperatures = sizeof(celsiusTemperatures) / sizeof(celsiusTemperatures[0]);
    
    std::cout << "Temperature readings (Celsius):\n";
    for (int i = 0; i < numTemperatures; ++i)
    {
        int celsius = celsiusTemperatures[i];
        int fahrenheit = celsius * 9 / 5 + 32;
        
        std::cout << celsius << "°C = " << fahrenheit << "°F";
        
        if (celsius < 0)
            std::cout << " (Below freezing)";
        else if (celsius > 30)
            std::cout << " (Hot)";
        
        std::cout << std::endl;
    }
    
    return 0;
}

Output:

Temperature readings (Celsius):
-40°C = -40°F (Below freezing)
-10°C = 14°F (Below freezing)
0°C = 32°F
15°C = 59°F
25°C = 77°F
35°C = 95°F (Hot)
50°C = 122°F (Hot)

Financial calculations

#include <iostream>

int main()
{
    // Bank account transactions (can be positive or negative)
    int accountBalance = 1000;
    int transactions[] = {500, -200, -150, 300, -75, -900};
    int numTransactions = sizeof(transactions) / sizeof(transactions[0]);
    
    std::cout << "Account Balance Tracking:\n";
    std::cout << "Starting balance: $" << accountBalance << std::endl;
    
    for (int i = 0; i < numTransactions; ++i)
    {
        int transaction = transactions[i];
        accountBalance += transaction;
        
        std::cout << "Transaction " << (i + 1) << ": ";
        if (transaction > 0)
            std::cout << "+$" << transaction << " (deposit)";
        else
            std::cout << "-$" << (-transaction) << " (withdrawal)";
        
        std::cout << " → Balance: $" << accountBalance;
        
        if (accountBalance < 0)
            std::cout << " (OVERDRAWN!)";
        
        std::cout << std::endl;
    }
    
    return 0;
}

Output:

Account Balance Tracking:
Starting balance: $1000
Transaction 1: +$500 (deposit) → Balance: $1500
Transaction 2: -$200 (withdrawal) → Balance: $1300
Transaction 3: -$150 (withdrawal) → Balance: $1150
Transaction 4: +$300 (deposit) → Balance: $1450
Transaction 5: -$75 (withdrawal) → Balance: $1375
Transaction 6: -$900 (withdrawal) → Balance: $475

Game scores and coordinates

#include <iostream>

int main()
{
    // Game coordinates (can be negative for left/down movement)
    struct Position
    {
        int x, y;
    };
    
    Position playerPos = {0, 0};  // Start at origin
    Position movements[] = {{5, 3}, {-2, 4}, {3, -7}, {-6, -1}};
    int numMoves = sizeof(movements) / sizeof(movements[0]);
    
    std::cout << "Player Movement Tracking:\n";
    std::cout << "Starting position: (" << playerPos.x << ", " << playerPos.y << ")\n";
    
    for (int i = 0; i < numMoves; ++i)
    {
        playerPos.x += movements[i].x;
        playerPos.y += movements[i].y;
        
        std::cout << "Move " << (i + 1) << ": (" 
                  << movements[i].x << ", " << movements[i].y 
                  << ") → Position: (" << playerPos.x << ", " << playerPos.y << ")\n";
    }
    
    // Calculate distance from origin
    int distanceFromOrigin = playerPos.x * playerPos.x + playerPos.y * playerPos.y;
    std::cout << "Final distance² from origin: " << distanceFromOrigin << std::endl;
    
    return 0;
}

Output:

Player Movement Tracking:
Starting position: (0, 0)
Move 1: (5, 3) → Position: (5, 3)
Move 2: (-2, 4) → Position: (3, 7)
Move 3: (3, -7) → Position: (6, 0)
Move 4: (-6, -1) → Position: (0, -1)
Final distance² from origin: 1

Integer overflow and underflow

Signed integers have limited ranges. Going beyond these limits causes overflow or underflow:

#include <iostream>
#include <climits>

int main()
{
    std::cout << "Demonstrating integer overflow/underflow:\n\n";
    
    // Near the maximum value of int
    int nearMax = INT_MAX - 2;
    std::cout << "Starting near INT_MAX:\n";
    std::cout << "nearMax = " << nearMax << std::endl;
    
    for (int i = 0; i < 5; ++i)
    {
        nearMax++;
        std::cout << "After increment: " << nearMax;
        
        if (nearMax == INT_MAX)
            std::cout << " (Maximum value reached!)";
        else if (nearMax < 0)  // Overflow occurred
            std::cout << " (OVERFLOW! Value wrapped around)";
        
        std::cout << std::endl;
    }
    
    std::cout << "\nStarting near INT_MIN:\n";
    int nearMin = INT_MIN + 2;
    std::cout << "nearMin = " << nearMin << std::endl;
    
    for (int i = 0; i < 5; ++i)
    {
        nearMin--;
        std::cout << "After decrement: " << nearMin;
        
        if (nearMin == INT_MIN)
            std::cout << " (Minimum value reached!)";
        else if (nearMin > 0)  // Underflow occurred
            std::cout << " (UNDERFLOW! Value wrapped around)";
        
        std::cout << std::endl;
    }
    
    return 0;
}

Output:

Demonstrating integer overflow/underflow:

Starting near INT_MAX:
nearMax = 2147483645
After increment: 2147483646
After increment: 2147483647 (Maximum value reached!)
After increment: -2147483648 (OVERFLOW! Value wrapped around)
After increment: -2147483647 (OVERFLOW! Value wrapped around)
After increment: -2147483646 (OVERFLOW! Value wrapped around)

Starting near INT_MIN:
nearMin = -2147483646
After decrement: -2147483647
After decrement: -2147483648 (Minimum value reached!)
After decrement: 2147483647 (UNDERFLOW! Value wrapped around)
After decrement: 2147483646 (UNDERFLOW! Value wrapped around)
After decrement: 2147483645 (UNDERFLOW! Value wrapped around)

Choosing the right signed integer type

Select based on the range of values you need to store:

#include <iostream>
#include <climits>

void analyzeRange(const char* description, long long minVal, long long maxVal)
{
    std::cout << description << ":\n";
    std::cout << "  Range needed: " << minVal << " to " << maxVal << std::endl;
    
    // Check which type can handle this range
    if (minVal >= SCHAR_MIN && maxVal <= SCHAR_MAX)
        std::cout << "  Recommendation: signed char (1 byte)\n";
    else if (minVal >= SHRT_MIN && maxVal <= SHRT_MAX)
        std::cout << "  Recommendation: short (2 bytes)\n";
    else if (minVal >= INT_MIN && maxVal <= INT_MAX)
        std::cout << "  Recommendation: int (4 bytes)\n";
    else if (minVal >= LONG_MIN && maxVal <= LONG_MAX)
        std::cout << "  Recommendation: long\n";
    else
        std::cout << "  Recommendation: long long (8 bytes)\n";
    
    std::cout << std::endl;
}

int main()
{
    std::cout << "Choosing appropriate signed integer types:\n\n";
    
    analyzeRange("Temperature in Celsius", -50, 50);
    analyzeRange("Student test scores", -10, 110);  // Including curve adjustments
    analyzeRange("Year (common era)", 1, 3000);
    analyzeRange("World population", 0, 10000000000LL);
    analyzeRange("Microscopic measurements", -1000000, 1000000);
    analyzeRange("Astronomical distances", -999999999999999LL, 999999999999999LL);
    
    return 0;
}

Output:

Choosing appropriate signed integer types:

Temperature in Celsius:
  Range needed: -50 to 50
  Recommendation: signed char (1 byte)

Student test scores:
  Range needed: -10 to 110
  Recommendation: short (2 bytes)

Year (common era):
  Range needed: 1 to 3000
  Recommendation: short (2 bytes)

World population:
  Range needed: 0 to 10000000000
  Recommendation: long long (8 bytes)

Microscopic measurements:
  Range needed: -1000000 to 1000000
  Recommendation: int (4 bytes)

Astronomical distances:
  Range needed: -999999999999999 to 999999999999999
  Recommendation: long long (8 bytes)

Best practices for signed integers

✅ Use int as the default choice

// Good: int is the most natural size for most calculations
int count = 0;
int temperature = -5;
int score = 95;

✅ Use appropriate literal suffixes for long types

// Good: Use proper suffixes for long literals
long bigNumber = 2147483648L;        // L suffix for long
long long veryBig = 9876543210LL;    // LL suffix for long long

// Avoid: These might not fit in int on all systems
// long bigNumber = 2147483648;      // Warning: might be too big for int
// long long veryBig = 9876543210;   // Warning: might be too big for int

✅ Check for overflow in critical calculations

#include <iostream>
#include <climits>

bool safeAdd(int a, int b, int& result)
{
    // Check for overflow before adding
    if (a > 0 && b > INT_MAX - a)
    {
        std::cout << "Addition would cause overflow!\n";
        return false;
    }
    if (a < 0 && b < INT_MIN - a)
    {
        std::cout << "Addition would cause underflow!\n";
        return false;
    }
    
    result = a + b;
    return true;
}

int main()
{
    int result;
    
    if (safeAdd(2000000000, 200000000, result))
        std::cout << "Safe addition result: " << result << std::endl;
    
    if (safeAdd(2000000000, 2000000000, result))
        std::cout << "This won't print due to overflow check\n";
    
    return 0;
}

❌ Avoid mixing signed and unsigned types

// Problematic: Mixing signed and unsigned can cause issues
int signedValue = -1;
unsigned int unsignedValue = 1;

// This comparison might not work as expected!
if (signedValue < unsignedValue)  // -1 gets converted to very large positive number
{
    std::cout << "This might not print when you expect it to!\n";
}

Summary

Signed integers are fundamental data types for storing positive and negative whole numbers:

  • Default choice: int is signed by default and suitable for most uses
  • Range considerations: Choose type based on the range of values you need
  • Available types: signed char, short, int, long, long long
  • Overflow/underflow: Values wrap around when exceeding the valid range
  • Best practices: Use appropriate suffixes, check for overflow in critical code, avoid mixing with unsigned types

Signed integers are essential for representing quantities that can be positive, negative, or zero - like temperatures, coordinates, account balances, and score adjustments.

Quiz

  1. What's the difference between int and signed int?
  2. How many values can a 16-bit signed integer represent?
  3. What happens when you increment the maximum value of a signed integer?
  4. Which signed integer type would you use to store a person's birth year?
  5. Why should you be careful when mixing signed and unsigned integers?

Practice exercises

Try implementing these signed integer programs:

  1. Create a temperature converter that handles negative temperatures in both Celsius and Fahrenheit
  2. Write a simple calculator that detects and reports integer overflow/underflow
  3. Implement a coordinate system for a 2D game that allows negative positions
  4. Create a program that determines the minimum signed integer type needed for a given range of values

Continue Learning

Explore other available lessons while this one is being prepared.

View Course

Explore More Courses

Discover other available courses while this lesson is being prepared.

Browse Courses

Lesson Discussion

Share your thoughts and questions

💬

No comments yet. Be the first to share your thoughts!

Sign in to join the discussion