Skip to main content

Signed and Unsigned Types

Integer types can be signed (negative and positive) or unsigned (only positive). Understanding signedness prevents bugs and overflow issues.

Signed Types (Default)

int x = -42;        // Signed by default
signed int y = -42; // Explicitly signed (same)

short s = -100;
long l = -1000;

Range (n bits): -2^(n-1) to 2^(n-1)-1

Unsigned Types

unsigned int count = 42;
unsigned char byte = 255;
unsigned long size = 1000000;

// Shorter form
unsigned x = 42; // unsigned int

Range (n bits): 0 to 2^n-1


char is Special

char c;           // Implementation-defined: signed or unsigned
signed char sc; // Guaranteed signed (-128 to 127)
unsigned char uc; // Guaranteed unsigned (0 to 255)

// For character data: use char
// For small integers: use signed/unsigned char

Mixing Signed and Unsigned

int x = -1;
unsigned int y = 1;

if (x < y) { // ⚠️ Danger! x converts to large unsigned
// This doesn't execute! -1 becomes 4294967295
}

// x (signed) converted to unsigned before comparison
// -1 → 4294967295 (wraps around)

Rule: When mixing, signed converts to unsigned.


Overflow Behavior

Signed Overflow (Undefined)

int x = INT_MAX;  // 2147483647
x++; // ❌ Undefined behavior!

Unsigned Overflow (Well-Defined)

unsigned int x = UINT_MAX;  // 4294967295
x++; // ✅ Wraps to 0 (modulo arithmetic)

unsigned int y = 0;
y--; // Wraps to UINT_MAX

Unsigned wraps around: 0 - 1 = 2^32 - 1


Common Pitfalls

Negative Loop

// ❌ Infinite loop!
for (unsigned int i = 10; i >= 0; i--) {
// i never < 0 (unsigned!)
}

// ✅ Fix: use signed
for (int i = 10; i >= 0; i--) {
// Works correctly
}

Subtraction

unsigned int a = 5;
unsigned int b = 10;

unsigned int diff = a - b; // ⚠️ Wraps! diff = huge number
int diff = a - b; // Still wrong: computes unsigned then converts

// ✅ Fix: cast before subtraction
int diff = static_cast<int>(a) - static_cast<int>(b); // -5

When to Use Each

Signed (default choice):

  • General integers
  • Can be negative
  • Math operations

Unsigned:

  • Bit manipulation
  • Sizes, counts (when > 0 guaranteed)
  • Interfacing with C APIs
  • Wrap-around behavior desired
// Typical usage
int temperature = -5; // Can be negative
unsigned int flags = 0xFF00; // Bit flags
size_t size = vec.size(); // Size (unsigned)

Summary

  • Signed: Can be negative, overflow is UB
  • Unsigned: 0+, overflow wraps (modulo)
  • Mixing: Signed converts to unsigned
  • Default: Use signed unless specific reason
// Generally prefer
int x = 10; // Signed by default

// Use unsigned for
unsigned int flags = 0; // Bit operations
size_t size = data.size(); // Sizes/counts