在c中虽然支持了变长数组,但是在使用的时候还是会有诸多限制。比如分配在栈上,也就是说不能返回变长数组的指针,同时还增加了栈溢出的风险,以下是几种不能使用的场景。
- 不能使用extern声明的长度
- 在struct members中定义长度
- 在static变量中定义长度
- 在函数定义中定义长度
extern int n;
int A[n]; // invalid: file scope VLA
extern int (*p2)[n]; // invalid: file scope VM
int B[100]; // valid: file scope but not VM
void fvla(int m, int C[m][m]); // valid: VLA with prototype scope
void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA
{
typedef int VLA[m][m]; // valid: block scope typedef VLA
struct tag {
int (*y)[n]; // invalid: y not ordinary identifier
int z[n]; // invalid: z not ordinary identifier
};
int D[m]; // valid: auto VLA
static int E[m]; // invalid: static block scope VLA
extern int F[m]; // invalid: F has linkage and is VLA
int (*s)[m]; // valid: auto pointer to VLA
extern int (*r)[m]; // invalid: r has linkage and points to VLA
static int (*q)[m] = &B; // valid: q is a static block pointer to VLA
}
好在GCC 中允许使用零长数组,把它作为结构体的最后一个元素时可以实现一些特别的功能,比如我最近想在共享内存上通过参数来动态配置大小,就使用了这种技术。我们来看一个动态字符串的例子。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct _str {
int len;
char data[0];
} Str;
int main()
{
char *test = "this is a test";
int len = strlen(test);
printf("test=%s len=%d\n", test, len);
Str *str = (Str*)malloc(sizeof(Str) + len * sizeof(char));
strcpy(str->data, test);
str->len = len;
printf("s=%s,len=%d\n", str->data, str->len);
return 0;
}
通过上述例子我们可以看出Str结构体中的data成功的指向了字符串的首地址,也没有非法访问的错误。
本文探讨了C语言中变长数组的限制,如不能返回变长数组的指针、增加栈溢出风险,并列举了若干不可用场景。然而,GCC允许在结构体中使用零长数组,作为一种特殊技巧,特别是在动态字符串处理和共享内存配置大小时。通过示例展示了如何在Str结构体中利用零长数组实现动态字符串功能。
936

被折叠的 条评论
为什么被折叠?



