Coming Soon
This lesson is currently being developed
Signed integers
Understand signed integer types and their ranges.
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
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
- What's the difference between
int
andsigned int
? - How many values can a 16-bit signed integer represent?
- What happens when you increment the maximum value of a signed integer?
- Which signed integer type would you use to store a person's birth year?
- Why should you be careful when mixing signed and unsigned integers?
Practice exercises
Try implementing these signed integer programs:
- Create a temperature converter that handles negative temperatures in both Celsius and Fahrenheit
- Write a simple calculator that detects and reports integer overflow/underflow
- Implement a coordinate system for a 2D game that allows negative positions
- Create a program that determines the minimum signed integer type needed for a given range of values
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions