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

时间:2017-01-03 10:59:44

标签: c c99 variable-length-array

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

因此,我并不熟悉使用C99引入的Variable Length Arrays

这个概念看起来很清楚,我不需要解释。我的问题是如果没有足够的可用内存用于这样的阵列,那么在运行时会发生什么?

我认为它依赖于o / s,可能依赖于编译器,GCC / Linux会做什么,以及Windows上的MS visual Studio C?任何X99或Posix定义?

2 个答案:

答案 0 :(得分:1)

从标准的角度来看,尝试分配具有实现无法容纳的大小的VLA会调用未定义的行为。由于标准不提供发现实现可以安全创建的大小数组的方法,并且不要求实现允许任何特定大小,因此任何创建大小大于1的VLA对象的尝试都应被视为调用未定义的行为,除非如果人们对实施的内部工作有足够的了解,以确定它能够处理的VLA的大小。

如果malloc()不可用,那么最好的选择可能是定义一大堆 无论哪种类型具有最粗略的对齐要求,都要将其地址存储到 一个volatile - 限定指针[指针本身所在的存储空间 应该如此合格]读回来,并将其解释为a的开头 内存池。不应该对原始数组对象进行其他使用。而 标准不能保证编译器不会确定它应该生成检查指针是否仍然标识原始对象的代码,如果是,则跳过将使用该指针访问任何其他内容的任何代码与原始对象的类型相比,在指针上使用volatile应该不太可能。

创建内存池后,您可以编写自己的内存管理 函数使用它,虽然任何时候指针都返回池中 可能需要使用volatile - 指针清洗黑客来防止 编译器使用基于类型的别名来证明处理最后的用法 存储作为其旧类型,相对于第一次使用而言是无序的 存储为新类型。

答案 1 :(得分:1)

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

这带来了一些危险。

  1. 分配给堆栈的空间可能会溢出。根据平台的不同,这可能会导致内核出现某种内存错误,这可能会导致平台动态分配更多的堆栈空间,或者可能导致覆盖其他内存。
  2. 在使用堆栈之外的保护页面进行自动堆栈增长和/或检测堆栈溢出的平台上,足够大的堆栈分配可能会“跳过”这些页面。在堆栈溢出通常被捕获的情况下,这可能会导致内存保护错误或更严重的内存损坏。
  3. 这些风险都不是特定于可变长度数组的,但是可变长度数组使得它们更容易被隐藏,直到使用特定参数调用代码。