sizeof 运算符与可变长度数组一起作为函数参数

sizeof operator in conjunction with variable-length array as function arguments

根据 GNU 关于 Arrays of Variable Length 的文档,可以使用 sizeof 运算符来确定传递给函数的可变长度数组的大小:

You can also use variable-length arrays as arguments to functions:

struct entry
tester (int len, char data[len][len])
{
  /* … */
}

The length of an array is computed once when the storage is allocated and is remembered for the scope of the array in case you access it with sizeof.

但是,当使用下面的完整代码示例尝试此示例时,sizeof 运算符 returns 指针的大小, 而不是 的大小分配的 vla,正如基于上面的 GNU 片段所预期的那样。

我知道在 C 中传递数组类似于传递指向数组第一个元素的指针,但是由于我们在这种情况下在函数签名中指定了大小,所以我希望行为模仿在声明数组的范围内使用 sizeof

我也意识到我可以使用 len 参数来计算大小;但为了方便和理解 GNU 实现,我仍然认为这是一个有趣的(如果不重要的话)问题。

提前感谢任何可以对此提供见解的人!

// file: vla.c
#include <stdio.h>

void foo(int len, char data[len][len]) {
  printf("sizeof \"foo\" data: %lu\n", sizeof(data));
}

int main(int argc, char * argv[]) {
  char data[argc][argc];
  printf("sizeof \"main\" data: %lu\n", sizeof(data));
  foo(argc, data);
}

编译使用:

gcc vla.c -o vla -std=c11

调用使用:

./vla 2 3 4 5

输出:

sizeof "main" data: 25
sizeof "foo" data: 8

分析:

main data 的大小是有道理的; argc 是 5,因此它是一个 (5 * 5 = 25) 字节的二维数组。

foo data 的大小预计也是 25,但实际上是指针的大小。看起来编译器没有使用它知道 foodata 的大小这一事实,因为它是函数签名的一部分。

声明为 char data[len][len] 的参数实际上是 char (*data)[len],一个指向 VLA 的指针。没有真正的数组参数这样的东西,声明中的第一个 len 是没有意义的。如果你使用 sizeof *data,你会返回 len,因为指向的类型被可变地修改。

如果您希望两个 len 都有意义,您可以传递一个指向整个数组的指针类型而不是指向第一个元素的指针,声明参数 char (*data)[len][len] .现在 sizeof *datalen*len。但是您需要使用 (*data)[i][j] 才能访问它。您还需要在调用函数时使用 & 运算符:

int l = 42;
char array[l][l];
foo(l, &array);