clanguage-lawyersizeofvariable-length-array

Is the operand of `sizeof` evaluated with a VLA?


An argument in the comments section of this answer prompted me to ask this question.

In the following code, bar points to a variable length array, so the sizeof is determined at runtime instead of compile time.

int foo = 100;
double (*bar)[foo];

The argument was about whether or not using sizeof evaluates its operand when the operand is a variable length array, making sizeof(*bar) undefined behavior when bar is not initialized.

Is it undefined behavior to use sizeof(*bar) because I'm dereferencing an uninitialized pointer? Is the operand of sizeof actually evaluated when the type is a variable length array, or does it just determine its type (how sizeof usually works)?


Edit: Everyone seems to be quoting this passage from the C11 draft. Does anyone know if this is the wording in the official standard?


Solution

  • Yes, this causes undefined behaviour.

    In N1570 6.5.3.4/2 we have:

    The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. 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.

    Now we have the question: is the type of *bar a variable length array type?

    Since bar is declared as pointer to VLA, dereferencing it should yield a VLA. (But I do not see concrete text specifying whether or not it does).

    Note: Further discussion could be had here, perhaps it could be argued that *bar has type double[100] which is not a VLA.

    Supposing we agree that the type of *bar is actually a VLA type, then in sizeof *bar, the expression *bar is evaluated.

    bar is indeterminate at this point. Now looking at 6.3.2.1/1:

    if an lvalue does not designate an object when it is evaluated, the behavior is undefined

    Since bar does not point to an object (by virtue of being indeterminate), evaluating *bar causes undefined behaviour.