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 width | Signed range | Unsigned range |
|---|---|---|
| 16 bits | -32,768 to 32,767 | 0 to 65,535 |
| 32 bits | -2,147,483,648 to 2,147,483,647 | 0 to 4,294,967,295 |
| 64 bits | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | 0 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 bitsshort: 16 bitsint: 32 bitslong: 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?”
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:
Integer.MAX_VALUEis2,147,483,647, the largest value that fits in a Javaint.- The first
printlndisplays that maximum value. max + 1tries to create2,147,483,648.- That value cannot fit in a 32-bit signed
int. - Java integer arithmetic wraps around, so the result becomes
-2,147,483,648, which isInteger.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
intIDs but needlongIDs as records grow. - Timestamps: Java timestamps and durations commonly use
longbecause seconds or milliseconds can exceedintlimits. - 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_tanduint32_tuseful.
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
| Feature | Java int | Java long | Typical C int | C int32_t |
|---|---|---|---|---|
| Width | Always 32 bits | Always 64 bits | Implementation-defined, often 32 bits | Exactly 32 bits when available |
| Signed? | Yes | Yes | Yes | Yes |
| Typical range | -2^31 to 2^31 - 1 | -2^63 to 2^63 - 1 | Depends on system | -2^31 to 2^31 - 1 |
| Best use | General whole-number values | Large counts, timestamps, IDs | General C arithmetic | Data formats requiring 32 bits |
| Signed integer | Unsigned integer |
|---|---|
| Represents negative and positive values | Represents zero and positive values only |
32-bit range: -2,147,483,648 to 2,147,483,647 | 32-bit range: 0 to 4,294,967,295 |
| Useful for balances and differences | Useful for bit flags, sizes, and binary protocol fields when appropriate |
Cheat Sheet
-32,768to32,767is the usual 16-bit signed range.-2,147,483,648to2,147,483,647is the 32-bit signed range.- Signed
n-bit range:-2^(n-1)to2^(n-1) - 1. - Unsigned
n-bit range:0to2^n - 1. - Java
intis always 32 bits. - Java
longis always 64 bits. - C
intis at least 16 bits and is commonly 32 bits, but its exact width is platform-dependent. - In C, include
<limits.h>and useINT_MIN/INT_MAXforintlimits. - In C, use
<stdint.h>types such asint32_twhen a precise width is needed. - In Java, use
Integer.MAX_VALUE,Integer.MIN_VALUE,Long.MAX_VALUE, andLong.MIN_VALUE. - Add
Lto Java long literals outside theintrange:2_147_483_648L. - Java
intarithmetic 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.
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
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.