【问题标题】:are "too large" objects with automatic storage duration undefined behaviour?具有自动存储持续时间未定义行为的“太大”对象?
【发布时间】:2018-04-23 01:03:09
【问题描述】:

关于 SO 的 recent question 关于“为什么在这种特定情况下在堆栈上分配大元素不会失败?”以及一系列有关“堆栈上的大型数组”或“堆栈大小限制”的其他问题让我搜索了标准中记录的相关限制。

我知道 C 标准没有指定“堆栈”,因此它没有为这种堆栈定义任何限制。但我想知道void foo() { char anArray[SIZE_X]; ... } 中的哪个SIZE_X 标准保证程序可以工作,如果程序超过这个SIZE_X 会发生什么。

我找到了以下定义,但我不确定这个定义是否真的是对具有自动存储持续时间的特定支持大小的对象的保证(参见this在线C11标准草案):

5.2.4.1 翻译限制

(1) 实现应至少能够翻译和执行 一个程序,其中至少包含一个实例 以下限制:

...

对象中的 65535 字节(仅在托管环境中)

这是否意味着实现必须支持在 void foo() { char anArray[SIZE_X]; ... } 之类的函数中对 SIZE_X 的值最大为 65535,并且对于 SIZE_X 的任何大于 65535 的值都是未定义的行为?

对于堆,调用malloc 返回NULL 让我控制请求“太大对象”的尝试。但是,如果程序“请求具有自动存储持续时间的太大对象”,特别是如果没有记录这样的最大大小,我该如何控制程序的行为,例如在一些limits.h?那么是否可以编写像checkLimits() 这样的可移植函数来支持“进入障碍”,例如:

int main() {
   if(! checkLimits()) {
      printf("program execution for sure not supported in this environment.");     
      return 1;
   } else {
      printf("might work. wish you good luck!"); 
   }
   ...
}

【问题讨论】:

  • 不会是堆栈溢出吧?
  • 为什么不是未定义的行为?
  • 我不知道标准文本需要什么,但作为记录,我遇到的编译器声称符合 C99 的最小实际空间只是不到 128 个字节。
  • 问题显然是堆栈溢出,但标准甚至没有提到堆栈这个词。也许我们应该向编译器作者提出要求,堆栈溢出程序(例如链接问题中的程序)不应该崩溃,因为它们已被完美定义。
  • checkLimits 这样的方法的问题在于,在很多情况下,它会受到可用内存量的限制。在运行多个程序的环境中,其他程序可以在您调用checkLimits 和实际调用foo 之间分配内存。

标签: c language-lawyer


【解决方案1】:

从技术上讲,实现只需要翻译和执行 一个 具有 65,535 字节对象(以及列出的其他内容)的程序即可符合标准。它可能会在所有其他人身上失败。

要知道更大的程序是否有效,您必须依赖具体实施的细节。大多数实现提供了超过 64 KiB 的堆栈空间,尽管它可能没有记录。可能存在用于调整允许的堆栈空间的链接器开关。

例如,对于当前 macOS 上的 ld 链接器,默认值为 8 MiB,-stack_size 开关可用于设置更多或更少(用于主线程)。

我要说的是,由于 C 标准规定诸如堆栈空间之类的环境限制可能会限制实现,因此除了某个特定示例程序必须工作这一事实之外,其他任何事情在技术上都是未定义的行为。

【讨论】:

  • "大多数实现提供的堆栈空间超过 64 KiB" --> 每年有数以亿计的嵌入式处理器使用 C 语言,资源有限,所以我对“大多数”有疑问.
  • @chux:如果您想成为技术人员,我希望这些都不是 C 实现,因为它们都没有记录 C 标准需要实现来记录的所有内容。我相信符合标准的 C 实现的数量为零,其中 51% 有大堆栈。
  • 当然同意51%的0部分。
猜你喜欢
  • 2015-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多