Question

C and Java Integer Ranges: Bits, int, and long Explained

cjavaintegermaxbit

Question

In C, I understand that an int on some systems may be 32 bits, but I have seen a range of -32,768 to 32,767. In Java, I have seen that integers range from -2,147,483,648 to 2,147,483,647.

How can the ranges differ when the number of bits appears to be the same? Also, is Java long a 32-bit type?

Short Answer

Integer ranges depend on both the number of bits and whether the type is signed or unsigned. The apparent discrepancy comes from mixing up 16-bit and 32-bit ranges: -32,768 to 32,767 is the usual range of a 16-bit signed integer, while -2,147,483,648 to 2,147,483,647 is the range of a 32-bit signed integer. In Java, int is 32 bits and long is 64 bits. In C, the size of int is implementation-defined, although it is commonly 32 bits today.

Concept

A computer stores an integer as a fixed number of binary digits, called bits. Each bit can be 0 or 1.

For an unsigned integer with n bits, every bit represents magnitude, so there are 2^n possible values:

0 through 2^n - 1

For a signed integer, one bit is effectively used to distinguish negative values from non-negative values. On modern systems using two's-complement representation, its range is:

-2^(n - 1) through 2^(n - 1) - 1

Therefore:

Type widthSigned rangeUnsigned range
16 bits-32,768 to 32,7670 to 65,535
32 bits-2,147,483,648 to 2,147,483,6470 to 4,294,967,295
64 bits-9,223,372,036,854,775,808 to 9,223,372,036,854,775,8070 to 18,446,744,073,709,551,615

The range -32,768 to 32,767 is not a 32-bit signed range. It is a 16-bit signed range.

Java defines primitive widths consistently on every platform:

  • byte: 8 bits
  • short: 16 bits
  • int: 32 bits
  • long: 64 bits

C is different: the C language does not require int to be 32 bits. It guarantees that int can represent at least -32,767 through 32,767; on most current desktop and server platforms, an int is 32 bits. A machine being described as “32-bit” does not, by itself, guarantee the size of every C type.

Mental Model

Think of bits as switches in a row.

  • A 16-switch row has 2^16, or 65,536, possible switch patterns.
  • A 32-switch row has 2^32, or 4,294,967,296, possible patterns.

A signed number needs to represent both debts and balances: negative and positive values. It splits the available patterns between them.

A 16-bit signed integer has about half its patterns for negatives and half for non-negative numbers, giving a maximum of 32,767.

A 32-bit signed integer has vastly more patterns, giving a maximum of 2,147,483,647.

So the important question is not only “is it an integer?” but also “how many bits does this particular integer type have?”

Take Quiz

Syntax and Examples

In Java, primitive integer sizes are fixed:

int score = 2_147_483_647;       // Largest int value
long population = 2_147_483_648L; // Needs long; L marks a long literal

System.out.println(Integer.MAX_VALUE);
System.out.println(Long.MAX_VALUE);

Integer.MAX_VALUE prints:

2147483647

Long.MAX_VALUE prints:

9223372036854775807

In C, use <limits.h> rather than assuming a width:

#include <stdio.h>
#include <limits.h>

int main(void) {
    printf("int range: %d to %d\n", INT_MIN, INT_MAX);
    printf("int bits: %zu\n", sizeof(int) * CHAR_BIT);
    return 0;
}

On a common modern system, this prints an int range of -2147483648 to 2147483647 and an int width of 32 bits. However, C code should check the platform requirements when an exact width matters.

For an exact-width 32-bit integer in C, use int32_t when it is available:

#include <stdint.h>

int32_t accountBalance = 2000000000;

Step by Step Execution

Consider this Java expression:

int max = Integer.MAX_VALUE;
System.out.println(max);
System.out.println(max + 1);

Step by step:

  1. Integer.MAX_VALUE is 2,147,483,647, the largest value that fits in a Java int.
  2. The first println displays that maximum value.
  3. max + 1 tries to create 2,147,483,648.
  4. That value cannot fit in a 32-bit signed int.
  5. Java integer arithmetic wraps around, so the result becomes -2,147,483,648, which is Integer.MIN_VALUE.

Output:

2147483647
-2147483648

Use long before performing the calculation when the result may exceed the int range:

long next = (long) max + 1;
System.out.println(next); // 2147483648

Real World Use Cases

Integer widths matter whenever a program stores counts, identifiers, sizes, money units, or binary data.

  • File sizes: A file can be larger than the maximum 32-bit signed value, so file APIs often use 64-bit values.
  • Database IDs: An application may begin with int IDs but need long IDs as records grow.
  • Timestamps: Java timestamps and durations commonly use long because seconds or milliseconds can exceed int limits.
  • Network protocols: A protocol may specify an unsigned 16-bit or 32-bit field. The exact width is part of the protocol contract.
  • Image processing: Pixel channels often use 8-bit unsigned values; image dimensions or total pixel counts may require larger integer types.
  • Embedded C programs: Hardware registers may be exactly 8, 16, or 32 bits, making uint16_t and uint32_t useful.
Take Quiz

Real Codebase Usage

In real code, developers avoid guessing numeric limits and make width choices intentional.

Use named limits

Java exposes limits through wrapper classes:

if (requestedCount > Integer.MAX_VALUE) {
    throw new IllegalArgumentException("Count is too large");
}

C exposes limits through standard headers:

#include <limits.h>

if (count > INT_MAX) {
    /* handle value that cannot fit in int */
}

Use long for calculations that can grow

Even if each input is an int, their product may not fit in one:

int width = 50_000;
int height = 50_000;

long pixels = (long) width * height;

Casting before multiplication is important. Otherwise, Java performs the multiplication as int first.

Use fixed-width types for binary formats in C

When a file format or API requires exactly 32 bits, C projects commonly prefer:

#include <stdint.h>

uint32_t checksum;
int64_t timestamp;

Validate at boundaries

When converting a large value into a smaller type, validate it first:

long total = 3_000_000_000L;

if (total > Integer.MAX_VALUE || total < Integer.MIN_VALUE) {
    throw new ArithmeticException("Value does not fit in int");
}

int safeTotal = (int) total;

Common Mistakes

Assuming a 32-bit machine means every C integer is 32 bits

A machine's “bitness” usually refers to its main architecture or pointer size. It does not define every C type.

/* Do not assume this is always 32 bits. */
int value;

Avoid the assumption by checking sizeof(int) * CHAR_BIT or using int32_t when an exact 32-bit type is required.

Mixing up Java int and long

Java int is 32 bits. Java long is 64 bits.

int small = 100;
long large = 100L;

Writing a too-large Java integer literal without L

This does not compile because the literal is interpreted as an int first:

long value = 2_147_483_648; // Broken: integer number too large

Add L:

long value = 2_147_483_648L;

Expecting overflow to produce an error automatically

Java int overflow wraps around in normal arithmetic:

int result = Integer.MAX_VALUE + 1;
System.out.println(result); // -2147483648

Use a larger type, range checks, or methods such as Math.addExact when overflow must be detected.

Confusing signed and unsigned ranges

A 32-bit unsigned value has a larger positive maximum than a signed one, but it cannot represent negative numbers. Java does not have a general uint32 primitive type; C does provide unsigned integer types.

Comparisons

FeatureJava intJava longTypical C intC int32_t
WidthAlways 32 bitsAlways 64 bitsImplementation-defined, often 32 bitsExactly 32 bits when available
Signed?YesYesYesYes
Typical range-2^31 to 2^31 - 1-2^63 to 2^63 - 1Depends on system-2^31 to 2^31 - 1
Best useGeneral whole-number valuesLarge counts, timestamps, IDsGeneral C arithmeticData formats requiring 32 bits
Signed integerUnsigned integer
Represents negative and positive valuesRepresents zero and positive values only
32-bit range: -2,147,483,648 to 2,147,483,64732-bit range: 0 to 4,294,967,295
Useful for balances and differencesUseful for bit flags, sizes, and binary protocol fields when appropriate
Take Quiz

Cheat Sheet

  • -32,768 to 32,767 is the usual 16-bit signed range.
  • -2,147,483,648 to 2,147,483,647 is the 32-bit signed range.
  • Signed n-bit range: -2^(n-1) to 2^(n-1) - 1.
  • Unsigned n-bit range: 0 to 2^n - 1.
  • Java int is always 32 bits.
  • Java long is always 64 bits.
  • C int is at least 16 bits and is commonly 32 bits, but its exact width is platform-dependent.
  • In C, include <limits.h> and use INT_MIN / INT_MAX for int limits.
  • In C, use <stdint.h> types such as int32_t when a precise width is needed.
  • In Java, use Integer.MAX_VALUE, Integer.MIN_VALUE, Long.MAX_VALUE, and Long.MIN_VALUE.
  • Add L to Java long literals outside the int range: 2_147_483_648L.
  • Java int arithmetic wraps on overflow unless you explicitly check for it.

FAQ

Is a C int always 32 bits?

No. C guarantees only a minimum range for int. It is commonly 32 bits on modern systems, but portable code should not assume that without checking.

Is Java long 32 bits?

No. Java long is always a signed 64-bit integer. Java int is the signed 32-bit integer type.

Why is the positive maximum one smaller than the negative magnitude?

With two's-complement signed representation, one bit pattern represents zero and there is one extra negative value. Therefore, a 32-bit signed type goes from -2^31 through 2^31 - 1.

What is the range of a 32-bit unsigned integer?

It ranges from 0 to 4,294,967,295 (2^32 - 1).

What happens when a Java int exceeds its maximum value?

Normal int arithmetic wraps around. Integer.MAX_VALUE + 1 becomes Integer.MIN_VALUE.

How can I find the size of a C integer type?

Use sizeof(type) * CHAR_BIT, with CHAR_BIT from <limits.h>. For limits, use macros such as INT_MIN and INT_MAX.

Should I always use long instead of int in Java?

No. Use int when its range is sufficient and the API expects it. Use long when values or calculations can exceed the int range.

Take Quiz

Mini Project

Description

Build a small Java range checker for values that may need to be stored as an int. This mirrors a common application boundary: receiving a large count or identifier and validating that it fits before narrowing it to a smaller type.

Goal

Read several long values, report whether each fits in a Java int, and safely convert valid values.

Requirements

Requirement 1

Take Quiz

Keep learning

Related questions

View more