Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The const keyword in C is a type qualifier that dictates an object’s value is immutable after its initial declaration. It instructs the compiler to treat the variable as read-only, triggering a compilation error if subsequent code attempts to modify the object’s state through direct assignment, increment, or decrement operations.

Syntax and Initialization

In C, unlike C++, a const variable is not strictly required to be initialized at the point of declaration. However, because it cannot be assigned to later, an uninitialized block-scope const variable will permanently hold an indeterminate value. An uninitialized file-scope const variable is zero-initialized via tentative definitions. The const qualifier can be placed before or after the type specifier.
const int max_count = 100; // Standard placement
int const min_count = 0;   // Equivalent placement

void example_function(void) {
    const int uninitialized_local; // Valid in C, but permanently holds an indeterminate value
}

Pointer Semantics

The interaction between const and pointers is dictated by the position of the const keyword relative to the asterisk (*). 1. Pointer to Constant Data The data being pointed to cannot be modified through the pointer, but the pointer itself can be reassigned to point to a different memory address.
void pointer_to_const_example(void) {
    const int *ptr_to_const;
    int const *ptr_to_const_alt; // Functionally identical to the above

    int x = 10;
    ptr_to_const = &x;           // Allowed: Reassigning the pointer
    // *ptr_to_const = 20;       // Error: Cannot modify the target data
}
2. Constant Pointer to Mutable Data The pointer’s memory address is locked, but the data at that address can be modified.
void const_pointer_example(void) {
    int y = 5;
    int z = 10;
    int * const const_ptr = &y;  // Initialization is optional in C, but practically necessary

    *const_ptr = 15;             // Allowed: Modifying the target data
    // const_ptr = &z;           // Error: Cannot reassign the pointer
}
3. Constant Pointer to Constant Data Both the pointer’s address and the data it points to are strictly immutable.
void strictly_const_example(void) {
    int w = 42;
    const int * const strictly_const_ptr = &w;
}

Typedef and Pointer Interaction

A critical semantic distinction occurs when applying const to a typedef of a pointer. The const qualifier applies to the alias itself (the pointer), not the underlying type. This results in a constant pointer to mutable data (Type * const), rather than a pointer to constant data (const Type *).
typedef int* IntPtr;

void typedef_const_example(void) {
    int a = 10;
    int b = 20;
    
    // 'const IntPtr' evaluates to 'int * const', NOT 'const int *'
    const IntPtr ptr = &a; 

    *ptr = 15;       // Allowed: The underlying data is mutable
    // ptr = &b;     // Error: The pointer itself is immutable
}

Memory Allocation and Linkage

The storage duration and memory segment of a const variable depend on its scope:
  • Global/Static Scope: Variables declared const at file scope or with the static keyword are typically allocated in the read-only data segment (.rodata) of the compiled binary. The operating system enforces hardware-level memory protection on this segment.
  • Local Scope: Automatic const variables declared inside a block reside on the stack. The immutability is enforced purely by the compiler’s semantic analysis, not by hardware memory protection.
By default, global const variables in C possess external linkage (unlike C++, where they default to internal linkage). They can be accessed across translation units using the extern keyword.

Constant Expressions vs. Const Variables

In C, a const-qualified variable is evaluated at run-time, not compile-time. It does not constitute a true “constant expression.” Consequently, a const variable cannot be used in contexts requiring strict compile-time evaluation, such as case labels or global array bounds.
const int size = 10;

// Error: 'size' is not a constant expression.
// Invalid at global scope because global array bounds require compile-time constants.
// int global_array[size]; 

void process_data(void) {
    int value = 10;
    
    // Valid in C99+: 'size' is evaluated at run-time to create a Variable Length Array (VLA).
    // Invalid in C89/C90.
    int local_array[size]; 

    switch(value) {
        // case size: // Error: 'size' cannot be used as a case label
        //    break;
        default:
            break;
    }
}

Undefined Behavior (UB)

Attempting to bypass the const qualifier by casting it away results in Undefined Behavior if the underlying object was originally declared as const.
void undefined_behavior_example(void) {
    const int immutable_val = 42;
    int *mutable_ptr = (int *)&immutable_val; // Casting away constness

    // UNDEFINED BEHAVIOR: Modifying an originally const object.
    // May cause a segmentation fault if stored in .rodata, 
    // or silent corruption if stored on the stack.
    *mutable_ptr = 99; 
}
Master C with Deep Grasping Methodology!Learn More