A C type controls a value's representation, valid operations, and minimum supported range. Except for char occupying exactly one C byte, the language does not promise one universal byte size for the basic types.
Use int for ordinary arithmetic, size_t for object sizes, and an exact-width type such as uint32_t only when a protocol, file format, or hardware interface requires that width.
C provides integer, floating-point, character, Boolean, and void types. The table shows a common modern implementation, not a language guarantee; inspect your compiler with sizeof, <limits.h>, and <float.h>.
| Type | Common Size | Format Specifier | Range | Description |
|---|---|---|---|---|
| int | 4 bytes | %d or %i | At least -32,767 to 32,767 | Integer numbers |
| float | 4 bytes | %f | At least six decimal digits of precision | Single-precision decimal |
| double | 8 bytes | %lf | At least ten decimal digits of precision | Double-precision decimal |
| char | 1 byte | %c | Signedness is implementation-defined | Single character |
| void | - | - | - | No value (used for functions/pointers) |
The signed, unsigned, short, and long modifiers change a numeric type. Their exact widths still depend on the implementation, but C guarantees the ordering sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long).
| Type | Size | Format Specifier | Range |
|---|---|---|---|
| short int | 2 bytes | %hd | -32,768 to 32,767 |
| unsigned int | 4 bytes | %u | 0 to 4,294,967,295 |
| long int | 4 or 8 bytes | %ld | -2,147,483,648 to 2,147,483,647 (min) |
| long long int | 8 bytes | %lld | -9.2 x 10^18 to 9.2 x 10^18 |
| unsigned long long | 8 bytes | %llu | 0 to 1.8 x 10^19 |
| unsigned char | 1 byte | %c | 0 to 255 |
| long double | 10 or 16 bytes | %Lf | Extended precision |
C also has derived data types that are built from primary types:
#include <stdio.h>
int main() {
int age = 25;
float price = 9.99f;
double pi = 3.14159265358979;
char grade = 'A';
printf("int: %d\n", age);
printf("float: %f\n", price);
printf("double: %lf\n", pi);
printf("char: %c\n", grade);
// Printing char as integer (ASCII value)
printf("char as int: %d\n", grade); // 65
return 0;
}
/*
Output:
int: 25
float: 9.990000
double: 3.141593
char: A
char as int: 65
*/
#include <stdio.h>
int main() {
// sizeof returns the size in bytes
printf("Size of char: %zu bytes\n", sizeof(char));
printf("Size of int: %zu bytes\n", sizeof(int));
printf("Size of float: %zu bytes\n", sizeof(float));
printf("Size of double: %zu bytes\n", sizeof(double));
printf("Size of long int: %zu bytes\n", sizeof(long int));
printf("Size of long long int: %zu bytes\n", sizeof(long long int));
printf("Size of unsigned int: %zu bytes\n", sizeof(unsigned int));
// Type modifiers in action
unsigned int population = 4294967295U; // max unsigned int
long long int bigNum = 9223372036854775807LL;
short int small = 32767;
printf("\nunsigned int: %u\n", population);
printf("long long int: %lld\n", bigNum);
printf("short int: %hd\n", small);
return 0;
}
/*
Output (64-bit system):
Size of char: 1 bytes
Size of int: 4 bytes
Size of float: 4 bytes
Size of double: 8 bytes
Size of long int: 8 bytes
Size of long long int: 8 bytes
Size of unsigned int: 4 bytes
*/
Use <limits.h> for integer limits, <float.h> for floating characteristics, and sizeof for the active implementation. <stdint.h> supplies exact-width types only when the implementation supports them; int_least32_t and int_fast32_t express minimum width or preferred speed instead.
Small integer types are promoted before most arithmetic. The usual arithmetic conversions then choose a common type for mixed operands. A negative int compared directly with size_t may become a very large unsigned value, so prove the value is nonnegative before converting.
Narrowing an integer can change its value. Converting an out-of-range floating value to an integer is undefined, while large integers converted to floating point may lose precision. Validate the destination range before a conversion that can discard information.
#include <stddef.h>\n#include <stdio.h>\n\nint main(void) {\n int index = -1;\n size_t count = 4;\n\n if (index >= 0 && (size_t) index < count) {\n puts("valid index");\n } else {\n puts("invalid index");\n }\n}
invalid index
The first condition proves that converting index to size_t cannot turn a negative value into a huge unsigned value.
| Need | Starting Type | Reason |
|---|---|---|
| Ordinary arithmetic | int | Natural integer operations on the target. |
| Object size or element count | size_t | Matches sizeof and library size parameters. |
| Pointer difference | ptrdiff_t | Represents valid pointer subtraction. |
| Exactly 32 protocol bits | uint32_t | Expresses an external width when available. |
| Decimal money | Checked scaled integer | Avoids binary floating-point rounding of decimal units. |
Try this next
0 of 2 completed
Explore 500+ free tutorials across 20+ languages and frameworks.