简体   繁体   English

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

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

I program embedded systems. 我对嵌入式系统进行编程。 One golden rule is that we never call malloc() ; 一个黄金法则是我们永远不要调用malloc() all data must be statically allocated at compile time. 所有数据必须在编译时静态分配。

Hence, I am not really familiar with Variable Length Arrays , which were introduced with C99. 因此,我对C99引入的可变长度数组不是很熟悉。

The concept seems clear enough, and I don't need it explaining. 这个概念似乎很清楚,我不需要解释。 My question is what happens at run time if there isn't enough free memory for such an array? 我的问题是,如果没有足够的可用内存用于这种阵列,在运行时会发生什么?

I would imagine that it is o/s dependent, maybe compiler dependent, to what would GCC/Linux do, and MS visual Studio C on Windows? 我可以想像,它与o / s有关,也许与编译器有关,与GCC / Linux和Windows上的MS visual Studio C有关? Any X99 or Posix definitions? 是否有X99或Posix定义?

From the point of view of the Standard, an attempt to allocate a VLA with a size the implementation cannot accommodate invokes Undefined Behavior. 从标准的角度来看,尝试以实现无法容纳的大小分配VLA会调用未定义行为。 Because the Standard provides no means of discovering what size array an implementation could safely create, and does not mandate that implementations allow any particular size, any attempt to create a VLA object with a size greater than 1 should be regarded as invoking Undefined Behavior except in cases where one happens to know enough about implementation's inner workings to determine the size of VLA it will be able to handle. 因为标准没有提供发现实现可以安全创建的大小数组的方法,并且没有强制实现允许任何特定大小,所以创建大小大于1的VLA对象的任何尝试都应视为调用未定义行为,除非碰巧对实现的内部工作了解得足够多的情况,以确定它可以处理的VLA的大小。

If malloc() is unavailable, one's best bet may be to define a large array of whatever type has the coarsest alignment requirement, store its address into a volatile -qualified pointer [the storage in which the pointer itself resides should be thus qualified] read it back, and interpret that as the start of a memory pool. 如果malloc()不可用,最好的选择是定义一个具有最大对齐要求的任何类型的大型数组,将其地址存储到一个volatile限定的指针中[该指针本身所在的存储空间应该因此被限定]读取然后将其解释为内存池的开始。 No other use should be made of the original array object. 原始数组对象不能有任何其他用途。 While the Standard wouldn't guarantee that a compiler wouldn't decide that it should generate code that checks whether the pointer still identifies the original object and, if it does, skipping any code that would use that pointer to access anything other than the original object's type, the use of volatile on the pointer should make that really unlikely. 尽管标准不能保证编译器不会决定是否应生成代码来检查指针是否仍标识原始对象,如果可以,则跳过使用该指针访问除原始对象以外的任何代码的代码。对象的类型,在指针上使用volatile应该确实不太可能。

Once a memory pool is created, you can write your own memory-management functions to use it, though any time a pointer is returned to the pool it may be necessary to use the volatile -pointer-laundering hack to prevent compilers from using type-based aliasing to justify treating the last uses of storage as its old type as unsequenced relative to the first uses of storage as a new type. 创建内存池后,您可以编写自己的内存管理函数以使用它,尽管任何时候将指针返回到池中,可能有必要使用volatile -pointer-laundering hack来防止编译器使用type-基于别名的处理可以证明将存储的最后使用作为旧类型视为相对于未使用的新类型。

Variable length arrays are typically allocated on the stack. 可变长度数组通常在堆栈上分配。 Like any other variable allocated on the stack this is normally done by subtracting from the stack pointer (or adding to it for an upwards-growing stack). 像在堆栈上分配的任何其他变量一样,这通常是通过从堆栈指针中减去(或为向上增长的堆栈添加)来完成的。 A frame pointer is likely to be used so that the function can keep track of it's stack frame in the face of dynamically determined changes to the stack pointer. 可能会使用帧指针,以便在动态确定对堆栈指针的更改时,函数可以跟踪其堆栈帧。 As with other stack allocations there is typically no error checking in this process. 与其他堆栈分配一样,此过程中通常不进行错误检查。

This brings a couple of dangers. 这带来了一些危险。

  1. The space allocated to the stack may be overflowed. 分配给堆栈的空间可能溢出。 Depending on the platform this may result in some kind of memory error from the kernel, it may result in the platform dynamically allocating more stack space or it may result in overwriting of other memory. 根据平台的不同,这可能导致内核出现某种内存错误,可能导致平台动态分配更多的堆栈空间,或者可能导致其他内存的覆盖。
  2. On platforms that use protection pages beyond the stack for automatic stack growth and/or detecting stack overflows a sufficiently large stack allocation may "skip over" those pages. 在使用超出堆栈保护页面的平台进行自动堆栈增长和/或检测堆栈溢出的平台上,足够大的堆栈分配可能会“跳过”这些页面。 This may lead to memory protection errors or worse memory corruption in cases where the stack overflow would normally have been caught. 如果通常会捕获堆栈溢出,则可能导致内存保护错误或更严重的内存损坏。

Neither of these risks is specific to variable length arrays but variable length arrays make them far more likely to lie hidden until the code is invoked with particular parameters. 这些风险都不是可变长度数组所特有的,但是可变长度数组使它们更有可能被隐藏,直到用特定参数调用代码为止。

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

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