const and volatile Keywords
Master the const and volatile type qualifiers. Learn to create read-only variables, pointers to const, const pointers, and understand volatile for hardware programming.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Use const to create read-only variables
- ✓Understand pointer to const vs const pointer
- ✓Know when to use volatile
- ✓Apply const correctness in functions
- ✓Combine const and volatile
01Type Qualifiers in C
const and volatile are type qualifiers that modify how the compiler treats variables. They are essential for writing safe, efficient, and hardware-aware code.
const
"This value should not be modified" - enables compiler optimizations and catches accidental changes.
volatile
"This value can change unexpectedly" - prevents compiler from caching or optimizing reads.
02The const Keyword
Basic Usage
1#include <stdio.h>23int main() {4 const int MAX_SIZE = 100; // Read-only variable5 const double PI = 3.14159; // Cannot be changed6 7 printf("MAX_SIZE = %d\n", MAX_SIZE);8 printf("PI = %.5f\n", PI);9 10 // MAX_SIZE = 200; // ERROR! Cannot modify const11 12 return 0;13}const vs #define
| Feature | const | #define |
|---|---|---|
| Type checking | Yes | No |
| Scope | Block/file scope | From definition to end of file |
| Memory | Has an address | Text substitution |
| Debugger visibility | Visible | Not visible |
03const with Pointers
With pointers, const can apply to the pointer itself, the data it points to, or both. The position of const matters!
1#include <stdio.h>23int main() {4 int x = 10, y = 20;5 6 // 1. Pointer to const int (can't change *p)7 const int* p1 = &x;8 // *p1 = 30; // ERROR! Can't modify data through p19 p1 = &y; // OK - can change where p1 points10 11 // 2. const pointer to int (can't change p)12 int* const p2 = &x;13 *p2 = 30; // OK - can modify data14 // p2 = &y; // ERROR! Can't change where p2 points15 16 // 3. const pointer to const int (can't change either)17 const int* const p3 = &x;18 // *p3 = 40; // ERROR!19 // p3 = &y; // ERROR!20 21 return 0;22}Memory Trick: Read Right to Left
const int* p= "p is a pointer to int that is const"int* const p= "p is a const pointer to int"const int* const p= "p is a const pointer to const int"
04const in Functions
Use const parameters to promise that a function won't modify the input data. This is called const correctness.
1#include <stdio.h>2#include <string.h>34// Function promises not to modify the string5int stringLength(const char* str) {6 int len = 0;7 while (str[len] != '\0') {8 len++;9 }10 return len;11}1213// Function promises not to modify the array14int findMax(const int* arr, int size) {15 int max = arr[0];16 for (int i = 1; i < size; i++) {17 if (arr[i] > max) {18 max = arr[i];19 }20 }21 return max;22 // arr[0] = 999; // ERROR! Can't modify const array23}2425int main() {26 const char* message = "Hello, World!";27 printf("Length: %d\n", stringLength(message));28 29 int numbers[] = {5, 2, 8, 1, 9};30 printf("Max: %d\n", findMax(numbers, 5));31 32 return 0;33}Expected Output:
Max: 9
05The volatile Keyword
volatile tells the compiler that a variable's value can change at any time, even if the code doesn't modify it. This prevents the compiler from caching the value in a register.
When to Use volatile
Hardware Registers
Memory-mapped I/O ports that change independently
Interrupt Handlers
Variables modified by interrupt service routines
Multi-threaded Code
Shared variables modified by other threads
Signal Handlers
Variables accessed by signal handlers
1#include <stdio.h>23// Hardware register example (embedded systems)4volatile int* const STATUS_REG = (volatile int*)0x40021000;56// Interrupt flag example7volatile int interrupt_flag = 0;89void wait_for_interrupt(void) {10 // Without volatile, compiler might optimize this to infinite loop11 while (interrupt_flag == 0) {12 // Wait - interrupt handler will set flag13 }14 interrupt_flag = 0; // Clear the flag15}1617// Simulated hardware polling18volatile int sensor_value;1920int read_sensor(void) {21 // Must read from memory each time, not cached register22 return sensor_value;23}volatile does NOT make code thread-safe!
For multi-threaded code, you also need proper synchronization (mutexes, atomics). volatile only prevents caching; it doesn't prevent race conditions.
06Combining const and volatile
A variable can be both const and volatile. This is common for read-only hardware registers.
1// Read-only hardware status register2// - const: your code shouldn't modify it3// - volatile: hardware can change it anytime4volatile const int* const STATUS_REG = (volatile const int*)0x40021000;56int check_status(void) {7 // Must read from memory (volatile)8 // Can't write to it (const)9 return *STATUS_REG;10}07Summary
const
- * Creates read-only variables
- * Position matters with pointers
- * Use for function parameters
- * Better than #define for constants
volatile
- * Prevents caching in registers
- * Use for hardware registers
- * Use for interrupt/signal variables
- * Does NOT provide thread safety
Test Your Knowledge
Related Tutorials
Bit Fields in Structures
Pack data efficiently with bit fields! Learn to define structure members that use specific numbers of bits, saving memory in embedded systems and protocols.
Bitmasks and Bit Manipulation
Work with individual bits! Set, clear, toggle, and check bits. Implement permission systems and flags efficiently.
Data Types & Variables
Learn to store different kinds of data: numbers (int), decimals (float), and characters (char). Understand how much memory each type uses.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!