When Is sizeof Evaluated at Runtime in C?

In the C programming language, the sizeof operator is almost universally resolved at compile time, yielding an integer constant with zero runtime performance cost. However, there is exactly one exception to this rule introduced in the C99 standard: sizeof is evaluated at runtime when its operand is a Variable Length Array (VLA) or an expression of a VLA type. Under these circumstances, the compiler cannot predict the array's dimension during compilation and must generate code to determine the size dynamically while the program executes.

The Standard Behavior: Compile-Time Evaluation

For standard types (primitives, structs, unions, pointers, and fixed-size arrays), sizeof inspects only the type of the operand. The expression itself is unevaluated.

For instance:

int x = 5;
size_t s = sizeof(x++);

In this scenario, x++ is never executed. The expression is discarded, the compiler replaces sizeof(x++) with the constant size of an int (typically 4 bytes), and x remains 5.

The Exception: Variable Length Arrays (VLAs)

Under ISO C99 and later standards (ISO/IEC 9899 ยง6.5.3.4), sizeof operates dynamically if the operand designates an entity with a variable length array type:

"If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant."

A VLA is an array whose size specifier is not an integer constant expression known at compile time, but rather a variable, function call, or runtime calculation.

void compute_size(int n) {
    int vla[n]; // Size depends on runtime parameter 'n'
    size_t bytes = sizeof(vla); 
}

In this code, the compiler cannot replace sizeof(vla) with a fixed numeric literal. Instead, it emits instructions to multiply the runtime value of n by sizeof(int) to calculate the total byte size at that exact point of execution.

Side Effects in VLA Dimension Expressions

Because VLAs require runtime evaluation, any side effects inside the size expression defining the VLA's dimensions will execute.

Consider this example:

#include <stdio.h>

int get_dimension(int *count) {
    (*count)++;
    return 10;
}

int main(void) {
    int count = 0;
    
    // sizeof applied to a VLA type name directly
    size_t size = sizeof(int[get_dimension(&count)]);

    printf("Count: %d\n", count); // Prints: Count: 1
    return 0;
}

When evaluating sizeof(int[get_dimension(&count)]), the function get_dimension() must be called at runtime so the program knows the array's length. Consequently, the side effect (count++) executes.

Pointers to Variable Length Arrays

Runtime evaluation also applies to pointer-to-VLA types:

void inspect_pointer(int rows, int cols) {
    int (*matrix_ptr)[cols];
    
    // Evaluated at runtime because (*matrix_ptr) has a VLA type
    size_t row_size = sizeof(*matrix_ptr); 
}

Here, *matrix_ptr dereferences to an array of size cols. Since cols is determined at runtime, sizeof(*matrix_ptr) evaluates cols * sizeof(int) dynamically. Note that sizeof(matrix_ptr) alone remains a compile-time constant because matrix_ptr is simply a pointer.

Modern C Standard Considerations

  • C99: VLAs were mandatory.
  • C11 and C17: VLAs became optional. Implementations defining the macro __STDC_NO_VLA__ do not support VLAs, meaning sizeof is purely a compile-time operator in those environments.
  • C23: VLAs remain conditionally supported, maintaining runtime evaluation for implementations that support them.