ISO C90 禁止使用可变长度数组。

7
我正在动态计算一个数组的大小,类似于下面这样:
void foo(size_t limit)
{
  char buffer[limit * 14 + 1];
}

但是只有GCC编译器会显示以下信息:
error: ISO C90 forbids variable length array ‘buffer’

在SO上搜索,我找到了这个答案C99 §6.7.5.2:

如果大小是不是整数常量表达式的表达式......每次评估它时,它应该有一个大于零的值。

因此,我重新声明了大小限制类型变量为:
void foo(const size_t limit)

但它仍然给我警告。这是GCC的一个bug吗?

12
好的,“C90 != C99”翻译成中文是“C90不等于C99”。 - user7116
2
size_t limit 声明为 const 不会改变任何东西。因为大小是在运行时确定的,所以它仍然是一个可变长度数组。 - Mysticial
GCC 告诉你,使用命令行选项时,默认情况下它会遵循 C90 标准进行编译。你引用的段落来自 C99。这是你问题的原因,而不是 limit 的类型。 - Pascal Cuoq
需要注意的是,GCC本身支持变长数组作为一种语言扩展,因此如果您不是在c99模式下编译,则可以使用它 - 但是除非您始终使用具有此类扩展或实现C99的VLAs的编译器,否则它不具备可移植性。 - wkl
1
只需使用gcc -std=c99 -pedantic ...调用gcc。 - pmg
6个回答

15

对一个变量进行const修饰并不会使它成为编译时常量(参见C99 6.6 §6中的整型常量表达式的定义),而在C99引入可变长度数组之前,数组大小需要是编译时常量。

很明显,对一个变量进行const修饰并不会使它成为编译时常量,特别是在函数参数的情况下,因为这些参数只有在调用函数时才会初始化。

以下是解决您问题的几种方法:

  • 通过-std=c99-std=gnu99将代码编译为C99
  • 使用malloc()来分配您的缓冲区
  • 如果可用,使用alloca(),这是您可以使用C90最接近的可变长度数组方法
  • 选择始终使用的最大缓冲区大小,并在给定的limit参数溢出时失败

顺便提一句,尽管C99允许使用可变长度数组,但仍然不合法将具有静态存储期的整数变量值用作具有静态存储期的数组的大小,无论是否const修饰。虽然原则上没有任何阻止这样做的东西,但如果整数变量在同一翻译单元中初始化,则需要特殊处理可见定义与定义位于不同翻译单元的变量,并且必须禁止尝试定义或要求多个编译步骤,因为“试探式定义”变量的初始化值直到整个翻译单元被解析之后才会知道。


6

const 在 C 语言中并不是引入常量,而是一个只读变量。

#define SIZE 16
char bla[SIZE];   // not a variable length array, SIZE is a constant

但是
const int size = 16;
char bla[size];   // C99 variable length array, size is a constant

3

C90不允许使用可变长度数组。但是,您可以使用c99-gcc编译器使其正常工作。

您正在使用c90-gcc编译,但查看C99规范。


2
不,这不是一个错误。在C90中你不能使用VLA。当你声明:
const size_t limit

那不是一个常量表达式。常量表达式应该是像字面值 666 这样的东西。

请注意,在这方面,C与C ++有很大的不同。即使是像这样的常量

const int i = 666;

在C语言中,NULL不是一个常量表达式。这就是为令常量值通常使用#define声明的主要原因。


非常感谢您的解释。出于好奇,为什么C90标准不接受像我尝试使用的常量表达式?因为如果我使用const类型,那么意味着我以后不能修改它,所以禁止它的原因是什么?而C99标准则不同,int值不需要至少是const类型。对我的糟糕英语表示抱歉。 :) - Jack
3
@Jack,你没有一个常量表达式,你有一个“const”变量。常量表达式可以是42或66。 - David Heffernan

0

根据您的问题所述,这是来自C99,而不是C90,您需要针对C99进行编译才能使用可变长度数组。


1
或者你可以使用alloca - James M
是的,但动态分配内存是另一回事。 - MByD
alloca和使用变长数组不是几乎完全相同吗?(因为它使用堆栈内存而不是堆内存) - James M

0

const限定的变量在标准意义上不是整数常量表达式。这必须是一个字面常量、枚举常量、sizeof或由它们组成的一些表达式。

如果可能,请切换到C99。gcc选项是-std=c99(如果您想要gnu扩展,则为gnu99)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接