C99 允许用结构体指针的成员指定 VLA 形参长度吗?
可以。只要 largeStructType 的结构体定义已经可见,且 size 是整数类型成员,int arr[largeStructPtr->size] 就是 C99 允许的数组形参写法。长度表达式可以通过 -> 引用成员,不必直接写成某个参数名。
标准为什么允许这种写法?
C99 允许用整数类型表达式指定数组长度,VLA 的长度不必是整数常量表达式。largeStructPtr->size 可以满足这个条件。
前一个参数 largeStructPtr 声明完成后,其名称可以用于后续参数声明,所以这里的参数顺序也符合要求。相关规定见 C99 合并勘误草案 N1256 的 §6.7.5.2 和 §6.2.1。标准条款
函数原型和函数定义有什么区别?
只有声明、没有函数体时,可以这样写:
void foo(largeStructType* largeStructPtr,
int arr[largeStructPtr->size]);
在函数原型作用域中,非整数常量的数组长度表达式按 * 处理,因此这条声明不会读取结构体成员。
函数定义中也可以使用相同写法,但原型中的处理规则并不适用于所有场景。VLA 长度表达式在运行时被求值时,值必须大于零;读取成员时,指针也必须有效。相关规则见 N1256 §6.7.5.2 第 5 段。原型与长度规则
可以怎样使用?
下面用一个只保留 size 成员的结构体演示:
typedef struct {
int size;
} largeStructType;
void foo(largeStructType* largeStructPtr,
int arr[largeStructPtr->size])
{
for (int i = 0; i < largeStructPtr->size; ++i) {
arr[i] = 0;
}
}
int main(void)
{
largeStructType info = {3};
int data[3] = {1, 2, 3};
foo(&info, data);
return 0;
}
这个调用中,长度为正,结构体指针有效,数组也有足够的可写元素。调用方可以传入固定长度数组,不必使用 VLA。
数组形参会自动检查长度吗?
不会。根据 N1256 §6.7.5.3 第 7 段,数组形参会调整为指针形参。这里 arr 在函数中的类型是 int*,sizeof arr 得到的是指针大小,不能用于计算调用方数组的元素个数。数组形参规则
示例中的循环要求调用方提供至少 size 个可写的 int 元素。方括号中的长度不会让函数自动分配数组,也不会自动阻止越界。
如果接口需要在函数体中先检查空指针或允许零长度,可以直接使用 int* arr 形参,再显式校验参数。原问题中写法的合法性应依据 C99 的表达式和形参规则判断;GCC 能编译只是辅助参考。
备注:内容仅供参考。
