繁体   English   中英

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

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

我对嵌入式系统进行编程。 一个黄金法则是我们永远不要调用malloc() 所有数据必须在编译时静态分配。

因此,我对C99引入的可变长度数组不是很熟悉。

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

我可以想像,它与o / s有关,也许与编译器有关,与GCC / Linux和Windows上的MS visual Studio C有关? 是否有X99或Posix定义?

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

如果malloc()不可用,最好的选择是定义一个具有最大对齐要求的任何类型的大型数组,将其地址存储到一个volatile限定的指针中[该指针本身所在的存储空间应该因此被限定]读取然后将其解释为内存池的开始。 原始数组对象不能有任何其他用途。 尽管标准不能保证编译器不会决定是否应生成代码来检查指针是否仍标识原始对象,如果可以,则跳过使用该指针访问除原始对象以外的任何代码的代码。对象的类型,在指针上使用volatile应该确实不太可能。

创建内存池后,您可以编写自己的内存管理函数以使用它,尽管任何时候将指针返回到池中,可能有必要使用volatile -pointer-laundering hack来防止编译器使用type-基于别名的处理可以证明将存储的最后使用作为旧类型视为相对于未使用的新类型。

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

这带来了一些危险。

  1. 分配给堆栈的空间可能溢出。 根据平台的不同,这可能导致内核出现某种内存错误,可能导致平台动态分配更多的堆栈空间,或者可能导致其他内存的覆盖。
  2. 在使用超出堆栈保护页面的平台进行自动堆栈增长和/或检测堆栈溢出的平台上,足够大的堆栈分配可能会“跳过”这些页面。 如果通常会捕获堆栈溢出,则可能导致内存保护错误或更严重的内存损坏。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM