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

时间:2018-02-07 10:10:37

标签: c gcc sizeof variable-length-array

根据cppreference

  

如果表达式的类型是可变长度数组类型, 表达式   被评估并计算它评估的数组的大小   在运行时。

这意味着:如果表达式的类型是VLA类型,则评估表达式。例如:

#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

4 个答案:

答案 0 :(得分:19)

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

C11 6.7.6.2/5

  

“如果大小是一个不是整数常量表达式的表达式:”/ - /“......每次计算它时,它的值应大于零。”

对于实际问题,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由于VLA导致第一个sizeof被评估,因此结果为0,但j仍为1,因为--jsizeof的一部分对于常规数组。

答案 1 :(得分:9)

示例中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;
}

答案 2 :(得分:3)

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

  

sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的带括号的名称。大小由操作数的类型确定。 结果是整数。如果操作数的类型是可变长度数组类型,则计算操作数;否则,不评估操作数,结果是整数常量

在表达式中:

sizeof(a[i++])

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

  

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

答案 3 :(得分:3)

对它进行规范性引用的克隆:

6.5.3.4 - The sizeof and _Alignof operators

  

sizeof运算符产生其操作数的大小(以字节为单位)   可以是表达式或类型的带括号的名称。大小是   根据操作数的类型确定。结果是整数。如果   操作数的类型是可变长度数组类型,操作数   被评估;否则,不评估操作数和结果   是一个整数常量。

如果您修复示例以生成具有VLA类型的表达式,则会对其进行评估

$PATH

Prints 2 on the last line,因为#include <stdio.h> int main() { int i = 1; int a[5][i]; printf("%zu\n",sizeof(a[i++])); printf("%d\n",i); return 0; } 会增加。