20

相关但不完全重复,因为它讨论了 C++:
我们可以给静态数组的大小一个变量吗

我在其中一个子文件中定义一个数组,如下所示。

static int arr[siz];

siz是子文件可用的全局变量。但是 gcc 编译器会产生以下错误:

<filename>: <line_num> : error : storage size of ‘arr’ isn’t constant

为什么我不能定义一个static可变大小的数组?

编辑:这似乎只是static int类型的问题。如果我将变量类型arrfrom更改为static intto int,错误就会消失,即使数组的大小仍然取决于 variable siz

4

4 回答 4

18

由于您声明的数组的大小不是恒定的,因此您拥有的是一个可变长度数组(VLA)。C99 标准允许 VLA,但有一些限制。您不能拥有带有staticextern存储类说明符的可变长度数组。

你有一个带有static存储规范的 VLA,它是 C99 标准不允许的。

参考:

c99 标准:6.7.5.2/8

示例 4 所有可变修改 (VM) 类型的声明必须在块范围或函数原型范围内。使用 static 或 extern 存储类说明符声明的数组对象不能具有可变长度数组 (VLA) 类型。但是,使用静态存储类说明符声明的对象可以具有 VM 类型(即,指向 VLA 类型的指针)。最后,所有使用 VM 类型声明的标识符都必须是普通标识符,因此不能是结构或联合的成员。

因此,如果您想要一个带有static存储说明符的动态大小数组,则必须使用在堆上分配的动态数组。

#define MAX_SIZE 256
static int* gArr;
gArr = malloc(MAX_SIZE * sizeof(int));

编辑:
回答您更新的问题:
当您static从声明中删除关键字时,声明数组的存储说明符从static全局更改为,请注意上面的标准引用,它清楚地提到了不允许使用 VLAstaticextern存储规范的限制。显然,您可以拥有具有全局存储规范的 VLA,这就是您删除static关键字后所拥有的。

于 2012-05-20T18:04:55.400 回答
5

您在编译时分配数组,因此编译器必须提前知道数组的大小。您必须在声明siz之前声明为常量表达式arr,例如:

#define siz 5

或者

enum ESizes
{
    siz = 5
};

或者,如果您需要在运行时确定它的大小,您可以使用以下命令在堆上分配它malloc

static int* arr;
arr = (int*)malloc(siz * sizeof(int))

编辑:正如 eddieantonio 所提到的,我的回答对 C89 有效。在 C99 中,允许声明可变大小的数组。

于 2012-05-20T17:09:21.767 回答
2

您不能定义任何可变大小的数组。那是因为arr[siz]让编译器(!)为您的数组分配内存(好吧,编译器创建了一个程序,那个..,但我们不要误入歧途)。但是,变量可以在运行时更改(!),这意味着编译器没有机会知道要分配多少内存。

你能做的是

static int* arr;
arr = (int*) calloc(siz,sizeof(int))

这些行导致程序在运行时分配内存,因此它的确切大小也可以在运行时定义。

于 2012-05-20T17:14:17.110 回答
0

您不能声明一个static可变大小的数组,因为它的空间是在数据段(或bss 段,如果是未初始化的变量)中分配的。因此,编译器需要在编译时知道大小,如果大小不是常量,编译器会报错。

其根本原因是数据段大小会影响正在生成的可执行文件的大小,这显然是在编译时创建的,因此必须固定。

于 2012-05-20T21:24:58.993 回答