【问题标题】:In which versions of the C standard are variable length arrays not part of the language, required, or optional?在 C 标准的哪些版本中,可变长度数组不是语言的一部分,是必需的还是可选的?
【发布时间】:2019-04-15 20:20:57
【问题描述】:

让我们考虑以下代码:

#include <stdio.h>

int main(){
    int size,i;
    scanf("%d",&size);
    int x[size];

    for(i=0;i<size;i++){
        x[i] = i;
    }

    for(i=0;i<size;i++){
        printf("%d\n", x[i]);
    }

    return 0;
}

我认为有些版本我们不能使用变量来声明数组以定义其大小,例如:

int x[size];

但我不确定是哪个版本。 这在所谓的 ANSI C 中是允许的吗?

【问题讨论】:

  • 事实上,在 C89 中不允许在范围开头以外的地方声明新变量的能力。
  • 这是一个所谓的“可变长度数组”,在 C99 标准修订版中成为语言的一部分,但在 C11 中成为可选
  • 我不认为这算作重复。这是要求澄清哪些 C 版本支持此功能,而另一个问题是询问可变长度数组如何工作。
  • 那里的答案解释了 VLA 出现的标准。这是 2019 年。我们有足够的 C 副本。

标签: c


【解决方案1】:

在 C89/C90 中,不能交错声明和语句,例如将 int x[size]; 声明(定义)放在 scanf() 之后 — 即使您将维度更改为编译时间常数。

在 C89/C90 中,不能使用可变长度数组 — 因此 int x[size]; 定义是不合法的,因为 size 不是编译时常量。

C99 编译器需要支持函数中(几乎)任意点的声明(它们仍然不能以标签开头)和可变长度数组 (VLA) 定义。

C11 编译器需要(几乎)支持函数中任何位置的变量定义。 C11 编译器可以选择支持 VLA(§6.10.8.3 Conditional feature macros§6.7.6.2 Array declarators),如果它们不支持,则应定义 __STDC_NO_VLA__

C18 在本讨论的所有方面都等同于 C11。

仅作记录:

  • C89 是 ANSI X3.159-1989
  • C90 是 ISO 9899-1990 — 其 ANSI 版本标有“ANSI X3.159-1989 的修订和重新指定”。主要区别在于语言和库的部分编号。
  • C99 是 ISO/IEC 9899:1999
  • C11 是 ISO/IEC 9899:2011
  • C18 是 ISO/IEC 9899:2018

当然,X3.159-1989 唯一不寻常的地方在于它是在 ISO 标准出现之前由 ANSI 发布的。但是,ANSI 也采用了每个后续的 ISO 标准,其他国家标准机构也采用了,例如 BSI(英国标准协会)和 DIN(德国标准化协会或德国标准化协会)。

还有一个修正案 1(针对 ISO 9899:1990)于 1994 年完成并于 1995 年发布。该修正案添加了标题并引入了二合字母并进行了其他各种更改。几乎从不单独考虑,尤其是 25 年后的现在。

请注意,GCC 将-ansi 选项视为等同于-std=c90,这可能会导致术语混淆。 ANSI 最初在 ISO 发布前一年左右发布了“ANSI C 标准”,但其目的始终是制定一个通用标准,并且 ANSI 在发布时认可了 ISO 9899:1990 标准。

【讨论】:

  • 关于交错语句和声明,您仍然可以在{} 中嵌套范围块,并且您可以在任何此类块的开头声明新变量,因此可以读取大小,然后在之后的嵌套块中声明该长度的 VLA。 ...还是我弄错了?
  • @hyde:是的,您可以在任何语句块的开头定义变量。在 C89/C90 中,即使大小在外部块中确定并且数组在内部块中定义,也不能拥有可变长度数组;数组的维度必须在编译时完全确定(通过对所有维度使用常量定义,或通过初始化以允许未指定第一个维度)。动态调整数组大小的唯一方法是通过动态内存分配——malloc() 等。规则在 C99 中都发生了变化。
  • 您可能想提一下,ANSI 一直在采用更新的 ISO/IEC 标准,而不仅仅是 ISO 9899:1990。这只会使 ANSI-C 仅指第一个版本的混淆永久化。 stackoverflow.com/a/4232714/1028434
  • @Fred:我加了一段强调ANSI、BSI、DIN等国家标准机构采用ISO标准。无论在世界其他地区受 ISO 和 ANSI 影响的情况如何,在 C 世界中,“ANSI C”指的是 C89,ISO C 可用于对比后来的标准。一方面,我同意你的看法;在另一个层面上,我认为你正在推动一个接近不可移动的物体。
  • 是的(关于我之前的评论),但是第一段的措辞可以更改,因为您可以通过添加嵌套块将声明放在 scanf 之后。我提出了这一点,因为许多人似乎认为您必须在 函数 的开头定义所有变量。
【解决方案2】:

这种数组,称为变长数组是在C99中加入的。 查看这篇关于现代 C 编程的精彩文章:

https://matt.sh/howto-c

【讨论】:

  • +1 表示有正确的(如果简洁的话)答案,-1 表示指向广泛资源的顶级入口点的链接,而不是指向 (1) 内较窄的位置资源;或 (2) 相关规范的字母和诗句(或找到被许可在答案中引用的东西,因此能够在链接中断中幸存下来)。
  • 这是一个很好的观察。指向语言参考中的特定规范对读者来说更可靠。为我未来的答案写下提示。
【解决方案3】:

ANSI-C (C89) 不允许使用变量初始化数组。

例如:

  int x = 5;
  int ia[x];

上面的这个例子是非法的。 ANSI-C 将数组初始化大小限制为常数。但是,您可以使用宏来定义数组的长度。

例子:

    #define MAX_ARRAY_SIZE 5
    int ia[MAX_ARRAY_SIZE];

【讨论】:

  • erm C99 允许可变长度数组。
  • 答案不完整,也没有提到 C99 VLA。无论如何,问题是一个明显的骗局。
  • 根据 ANSI 网站:The Current C Programming Language Standard – ISO/IEC 9899:2018 (C18)。因此,当人们提到 ANSI 标准时,它不仅限于 C89。
  • @Fred:按照通常的说法,部分由 GCC 编译器强制执行,ANSI 标准是指 C89 标准 X3.158-1989,在 ANSI/ISO 9899-1990 标准发布之前发布(标有“ ANSI X3.159-1989") 的修订和重新指定。主要区别在于 ANSI 和 ISO 标准中的部分编号。 GCC 助长了这种混淆,因为选项-ansi 等同于-std=gnu90,而且很多人将“ANSI C”视为C89 或C90 标准——它们实际上是等效的标准。否则,狡辩实际上对任何人都没有太大帮助。
  • @JonathanLeffler 也许你认为这很常见,这很好,但我不同意。我看到的常见做法是 ANSI-C 指的是标准,而不是编译器支持的附加扩展。同样根据 GCC 手册 -ansi 相当于 -std=c90 NOT -std=gnu90。所以即使在这里 ANSI 指的是不使用 GNU 方言和某些 GNU 扩展。我不得不说你的评论也不是很有帮助。
猜你喜欢
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 2021-04-02
相关资源
最近更新 更多