C99 如何处理无法在 运行 时间创建可变长度数组?

How does C99 handle being unable to create a variable length array at run time?

我编写嵌入式系统。一条黄金法则是我们 从不 调用 malloc();所有数据必须在编译时静态分配。

因此,我对 Variable Length Arrays 不是很熟悉,它是在 C99 中引入的。

概念已经很清楚了,不用解释了。我的问题是,如果没有足够的可用内存用于此类数组,在 运行 时会发生什么情况?

我想它是 o/s 依赖的,也许是编译器依赖的,GCC/Linux 会做什么,而 MS visual Studio C 在 Windows 上?任何 X99 或 Posix 定义?

从标准的角度来看,尝试分配大小为实现无法容纳的 VLA 会调用未定义行为。因为标准没有提供任何方法来发现一个实现可以安全地创建什么大小的数组,并且不强制实现允许任何特定大小,所以任何尝试创建一个大小大于 1 的 VLA 对象都应该被视为调用未定义的行为,除非恰好足够了解实现的内部工作原理以确定它能够处理的 VLA 大小的情况。

如果 malloc() 不可用,最好的办法可能是定义一个大数组 无论哪种类型具有最粗略的对齐要求,都将其地址存储到 一个 volatile 限定的指针 [指针本身所在的存储 应该因此有资格]读回,并将其解释为一个开始 内存池。不应将原始数组对象用于其他用途。尽管 该标准不保证编译器不会决定它应该生成代码来检查指针是否仍然标识原始对象,如果是,则跳过任何将使用该指针访问除原始对象之外的任何内容的代码类型,在指针上使用 volatile 应该不太可能。

创建内存池后,您可以编写自己的内存管理 函数来使用它,尽管任何时候一个指针返回到池它 可能需要使用 volatile-pointer-laundering hack 来防止 编译器使用基于类型的别名来证明处理最后一次使用是合理的 存储作为其旧类型相对于第一次使用是无序的 存储作为一种新类型。

可变长度数组通常分配在堆栈上。与在堆栈上分配的任何其他变量一样,这通常是通过从堆栈指针中减去(或为向上增长的堆栈添加)来完成的。可能会使用帧指针,以便函数可以在面对动态确定的堆栈指针更改时跟踪其堆栈帧。与其他堆栈分配一样,此过程中通常没有错误检查。

这会带来一些危险。

  1. 分配给栈的space可能溢出了。根据平台的不同,这可能会导致内核出现某种内存错误,可能会导致平台动态分配更多堆栈 space 或者可能会导致覆盖其他内存。
  2. 在使用堆栈之外的保护页面进行自动堆栈增长的平台上 and/or 检测到堆栈溢出时,足够大的堆栈分配可能 "skip over" 这些页面。在通常会捕获堆栈溢出的情况下,这可能会导致内存保护错误或更严重的内存损坏。

这些风险都不是特定于可变长度数组,但可变长度数组使它们更有可能隐藏起来,直到使用特定参数调用代码。