Lesson content
Read, practise, then check your understanding
A type determines how bytes are interpreted, which operations are permitted, and how values are passed. C’s fundamental types include character, signed and unsigned integers, floating-point types, and _Bool. Arrays, pointers, functions, structures, unions, and enumerations build on them.
Integer types
The standard integer family is char, short, int, long, and long long, each except plain char having signed and unsigned forms. Their exact widths are implementation-defined, but the ordering guarantees each later type can represent at least as much range as the previous one.
Use <limits.h> for ranges and <stdint.h> when a fixed or minimum width matters:
#include <stdint.h>
#include <stdio.h>
int main(void) {
int32_t temperature_milli_c = 23500;
uint64_t packet_count = 9000;
printf("%d, %llu\n", temperature_milli_c,
(unsigned long long)packet_count);
}
Exact-width types such as int32_t exist only when the implementation supports them. Types like int_least32_t and uint_fast16_t provide portable alternatives.
Floating point and boolean
float, double, and long double trade storage and speed for precision and range. Decimal fractions are often not exactly representable in binary, so compare calculated floating values using a meaningful tolerance.
#include <math.h>
#include <stdbool.h>
bool nearly_equal(double a, double b) {
return fabs(a - b) < 1e-9;
}
stdbool.h defines bool, true, and false for language editions before C23’s updates.
Declarations and initialization
Initialize variables before reading them. Automatic local variables otherwise hold indeterminate values.
int attempts = 0;
double average = 0.0;
char grade = 'A';
Character constants use single quotes; strings use double quotes. A char is an integer type large enough to hold one byte, not inherently a full Unicode character.
Conversions
Usual arithmetic conversions bring operands to compatible types. Mixing signed and unsigned values can produce surprising results because a negative signed operand may convert to a large unsigned value.
size_t length = 10;
int index = -1;
if (index >= 0 && (size_t)index < length) {
/* index is valid */
}
Use explicit casts only after proving the conversion is valid; a cast can silence a warning without making a value safe.
sizeof and portable output
sizeof(type) and sizeof expression return the storage size in bytes as size_t. Use %zu to print it:
printf("int uses %zu bytes\n", sizeof(int));
Do not assume that a byte is eight bits, that int is 32 bits, or that pointers fit in an integer. Use standard types and limits that express the program’s real requirement.
Knowledge check
Answer every question correctly to complete this chapter.
0 of 10 checks passed
Your progress is saved on this device.