为何C语言函数参数数组声明可写表达式?代码编译疑问解析
C语言函数参数数组长度表达式的疑问解答
问题代码
#include <stdlib.h> #include <string.h> #ifdef __GNUC__ __attribute__((__const__)) #endif int len(char** array) { int i; for (i = 0; array[i]; i++); return i; } void inner_len(char** array, int out[len(array)]) { int i; for (i = 0; i < len(array); i++) { out[i] = strlen(array[i]); } } int main() { char* array[] = { "hello", "world", NULL }; int ilen[1]; inner_len(array, ilen); }
核心疑问
inner_len函数声明中的int out[len(array)]表达式是否会被编译器忽略?为何编译时无警告错误?- C语言为什么允许在函数参数的数组声明中写入表达式?
解答
1. 函数参数中的数组长度表达式为何没触发警告,是否被忽略?
首先要明确C语言的核心规则:函数参数列表中的数组声明会被自动调整为指针类型。也就是说int out[len(array)]本质等价于int *out,这个长度表达式在函数声明阶段并不会限制指针的指向,编译器不会用它来做数组边界的强制检查。
你之前遇到GCC对错误数组长度警告的情况,大概率是使用了常量表达式作为数组长度(比如int out[5]),且传入的数组长度明显不匹配,这时编译器能在编译期验证出问题。但这里的len(array)是函数调用表达式,属于运行时才能确定的值——即便len加了__const__属性,编译器也不会主动跨函数推导其返回值为常量2——所以编译器无法在编译期预判out需要的长度,自然不会触发警告。
另外,这段代码运行时会出现数组越界(ilen[1]长度为1,但inner_len会写入2个元素),但越界属于运行时错误,编译期编译器无法完全检测到这类问题,除非开启更严格的静态分析选项(即便如此,也未必能推导len(array)的结果)。
2. C语言为何允许函数参数数组声明中写入表达式?
这是C99标准引入的**可变长度数组(VLA)**特性带来的合法用法。可变长度数组允许数组的长度由运行时的表达式决定,而函数参数列表中,后续参数可以使用前面已经声明的参数来定义数组长度。
虽然函数参数中的VLA最终会退化为指针,但这个长度表达式并非完全无用:
- 它可以作为文档,明确提示调用者该参数预期的数组长度;
- 如果在函数内部使用
sizeof(out),编译器会结合这个长度表达式计算出数组的字节大小(这是VLA的特性,sizeofVLA会在运行时计算); - 部分编译器(比如GCC)在开启特定选项时,会基于这个长度表达式做一些静态检查,提升代码安全性。
内容的提问来源于stack exchange,提问作者Tenobaal
相关产品推荐
相关产品推荐

