c - 具有副作用的可变长度数组参数大小表达式

标签 c parameter-passing language-lawyer variable-length-array

这个问题源于Eric Postpischil在in another thread.中所作的评论。

我很难理解将可变长度数组(VLA)用作函数参数:


不检查数组大小。
无法从数组中恢复数组大小,因为标准类型调整数组->指针也适用于VLA,如下面的sizeof()调用所示。即使完全有可能在堆栈上传递整个数组,就像在定义VLA时在堆栈上创建VLA一样。
大小必须与指针一样作为附加参数传递。


那么,如果该语言没有提供任何优势并且像指针的任何其他数组参数一样进行调整,为什么该语言允许使用VLA参数声明函数呢?如果语言未使用大小表达式(例如,检查实际参数的大小)并且在函数内部无法获得大小表达式(仍然需要为此传递一个显式变量),为什么要对其进行评估?

为了使我更困惑,请考虑以下程序(实时示例here)。所有函数声明显然都是等效的。但是,正如Eric在另一个线程中指出的那样,函数声明中的参数大小表达式是在运行时求值的。大小表达式不会被忽略。

我不清楚这会带来什么好处,因为大小及其评估没有影响(可能的副作用除外)。特别是要重复一遍,该信息不能被函数内部的代码使用。最明显的变化是将VLA传递给类似结构的堆栈。毕竟,它们通常也位于调用方的堆栈中。但是,就像使用恒定长度的数组一样,在声明时已经将类型调整为指针-以下所有声明都是等效的。尽管如此,仍会评估无用和废弃的数组大小表达式。

#include <stdio.h>

// Nothing to see here.
extern void ptr(int *arr);

// Identical to the above.
extern void ptr(int arr[]);

// Still identical. Is 1 evaluated? Who knows ;-).
extern void ptr(int arr[1]);

// Is printf evaluated when called? Yes.
// But the array is still adjusted to a pointer.
void ptr(int arr[printf("Call-time evaluation of size parameter\n")]){}

// This would not compile, so the declarations above must be equivalent.
// extern void ptr(int **p);

int main()
{
    ptr(0);
    ptr(0);

    return 0;
}

最佳答案

...可以省略size变量和...在运行时将要评估的大小...;但是有什么用呢?


顶级大小信息丢失😢,在array参数中现在是一个指针参数。然而,有了2D VLA函数参数,这些参数变成了指向1D数组的指针,代码就知道了该数组的维数。

void g(size_t size, size_t size2, int arr[size][size2]) {
  printf("g: %zu\n", sizeof(arr));
  printf("g: %zu\n", sizeof(arr[0]));
}

int main(void) {
  int arr[10][7];
  g(10, 7, arr);
}


输出量

g: 8   pointer size
g: 28  7 * int size




或者,将指针传递给数组。

void g2(size_t size, size_t size2, int (*arr)[size][size2]) {
  printf("g2: %zu\n", sizeof(arr));
  printf("g2: %zu\n", sizeof(*arr));
}

int main(void) {
  int arr[10][7];
  g2(10, 7, &arr);
}


输出量

g2: 8    pointer size
g2: 280  10 * 7 * int size

关于c - 具有副作用的可变长度数组参数大小表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54380305/

相关文章:

c - 用于引导加载程序设置的链接器文件 vector 表

Android 和 Google-app-engine createuploadURL - 如何传递附加参数(即电子邮件地址)

python - 在参数化中传递 pytest fixture

perl - @_ 在 Perl 子程序中是如何工作的?

c++ - C++中对象和变量的区别

c - 有没有办法在 GCC 中编译程序而无需汇编?

c - 有没有一种方法可以将指针传递给变量,而无需根据函数原型(prototype)事先定义它,如果其参数需要指针作为一个变量?

c - 使用 union 检测字节顺序是否安全?

c++ - 常量 T{};作品,常量T;当 T 是非 POD 时失败,

python - 使用 Python 从双指针 C++ 函数中读取字符串