具有可变长度数组类型的 Sizeof 运算符

Sizeof operator with variable-length array type

根据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.

意思是:如果expression的类型是VLA类型,那么expression被求值。例如:

#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;
}

所以,根据参考资料,这里的i变成了1。但是,使用我的 GCC 编译器,i 打印为 0.

Wandbox Demo

你例子中sizeof中的表达式是int,不是vla。如果是 vla,一切都会起作用:

#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;
}

来自 C Standards#6.5.3.4p2 [强调我的]

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.

表达式中:

sizeof(a[i++])

a[i++] 不是 VLA,而是一个下标运算符表达式,结果是一个整数。因此,操作数未被评估,出于同样的原因,编译器对此语句发出警告:

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

取其规范引用的克隆词:

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.

它会被评估,如果你修改你的例子来产生一个 VLA 类型的表达式,一种这样的方式

#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,因为i递增。

首先,请注意数组的大小不能为零,无论是否是 VLA。所以你的代码调用了未定义的行为。

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."


至于实际问题,a[i++]int类型,不是VLA类型。

为了得到副作用,必须涉及到VLA数组类型本身,比如sizeof(a)。只有这样,操作数才会评估副作用。一个例子来说明这一点:

#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;
}

此处 i 最终为 0,因为第一个 sizeof 由于 VLA 而被评估,但 j 仍然为 1,因为 --j 是 [= 的一部分15=] 对于常规数组。