msc
msc

Reputation: 34598

Sizeof operator with variable-length array type

According to cppreference:

If the type of expression is a variable-length array type, expression is evaluated and the size of the array it evaluates to is calculated at run time.

It means: if the type of expression is a VLA type, then expression is evaluated. For example:

#include <stdio.h>

int main() {
    int i = 0;
    int a[i];
    printf("%zu\n",sizeof(a[i++]));
    printf("%d\n",i); // Here, print 0 instead of 1
    return 0;
}

So, according to the reference, here i becomes 1. But, with my GCC compiler, i prints as 0.

See Wandbox Demo.

Upvotes: 13

Views: 1783

Answers (4)

Uprooted
Uprooted

Reputation: 971

The expression in sizeof in your example is int, and not vla. If it were vla, all would work:

#include <stdio.h>

int main() {
    int i = 5;
    int a[i][i];
    printf("%zu\n",sizeof(a[--i]));
    printf("%d\n",i); // Here, print 4
    return 0;
}

Upvotes: 9

Lundin
Lundin

Reputation: 213842

First of all, please note that an array cannot have size zero, be it a VLA or not. So your code invokes undefined behavior.

C11 6.7.6.2/5

"If the size is an expression that is not an integer constant expression:" /--/ "...each time it is evaluated it shall have a value greater than zero."


As for the actual problem, a[i++] is of type int, not of VLA type.

In order to get the side-effect, you must involve the VLA array type itself, such as sizeof(a). Only then is the operand evaluated for side effects. One example to illustrate this:

#include <stdio.h>

int main() {
    int i=1, j=1;
    int a[i][j];
    int b[1][1];

    (void) sizeof(a[--i]);
    (void) sizeof(b[--j]);
    printf("%d %d", i, j);

    return 0;
}

Here i ends up as 0 since the first sizeof is evaluated because of the VLA, but j remains 1 because --j was part of a sizeof for a regular array.

Upvotes: 20

To take the word of a clone of a normative references for it:

6.5.3.4 - The sizeof and _Alignof operators

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.

It would be evaluated, if you fix your example to produce an expression with VLA type, one such way

#include <stdio.h>

int main() {
    int i = 1;
    int a[5][i];
    printf("%zu\n",sizeof(a[i++]));
    printf("%d\n",i);
    return 0;
}

Prints 2 on the last line, because i is incremented.

Upvotes: 3

H.S.
H.S.

Reputation: 12669

From C Standards#6.5.3.4p2 [emphasis mine]

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.

In the expression:

sizeof(a[i++])

the a[i++] is not VLA but a subscript operator expression resulting in an integer. So, the operand is not evaluated and for the same reason, compiler is giving warning on this statement:

warning: expression with side effects has no effect in an unevaluated context

Upvotes: 3

Related Questions