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, meaningsizeofis purely a compile-time operator in those environments. - C23: VLAs remain conditionally supported, maintaining runtime evaluation for implementations that support them.