为什么C没有为数组定义最小大小?

C标准定义了许多下限/上限( 转换限制 ),并强制实现应满足每个转换。 为什么没有为数组大小定义这样的最小限制? 以下程序将编译正常并可能产生运行时错误/段错误,并将调用未定义的行为

int main() { int a[99999999]; int i; for(i=0;i<99999999;i++) a[i]=i; return 0; } 

可能的原因可能是在自动存储上分配了本地数组,它取决于分配的堆栈帧的大小。 但为什么不像C定义的其他限制那样达到最小限度?

让我们忘记上面提到的未定义的情况。 考虑以下:

 int main() { int a[10]; int i; for(i=0;i<10;i++) a[i]=i; return 0; } 

在上面,是什么让我保证本地数组(尽管非常小)将按预期工作,并且不会因分配失败而导致未定义的行为?

虽然这种小型arrays的分配不太可能在任何现代系统上失败。 但是C标准没有定义满足要求,编译器也没有(至少GCC没有)报告分配失败。 只有运行时错误/未定义的行为才有可能。 困难的部分是没有人能够判断任意大小的数组是否会因分配失败而导致未定义的行为。

请注意,我知道我可以使用动态数组(通过malloc和朋友)来实现此目的,并可以更好地控制分配失败。 我更感兴趣的是为什么没有为本地数组定义这样的限制。 此外,全局数组将存储在静态存储中,并将增加编译器可以处理的可执行文件大小。

MINIMUM限制是1个元素的数组。 为什么你会有“限制”? 当然,如果你永远递归地调用一个函数,1的数组可能不适合堆栈,或者调用下一次调用函数的调用可能不适合堆栈 – 解决这个问题的唯一方法就是知道编译器中堆栈的大小 – 但是编译器实际上并不知道在那个阶段堆栈有多大 – 更不用说极其复杂的调用层次结构的问题是几个不同的函数调用相同的函数,可能是递归和/或堆栈的几个相当大的消费者层 – 你如何调整堆栈的大小 – 可能永远不会遇到最糟糕的情况,因为其他事情要求这不会发生 – 例如,一个函数中的最坏情况只是当输入文件为空时,但另一个函数中最坏的情况是当同一文件中存储了大量数据时。 像这样的很多很多变化。 确定它太不可靠了,所以迟早它会变成猜测或许多误报。

考虑一个包含数千个函数的程序,所有这些函数都调用相同的日志记录函数,该函数需要堆栈上的200字节数组来临时存储日志输出。 它几乎从主要向上的所有function调用。

局部变量的MAXIMUM取决于堆栈的大小,就像我上面说的那样,这不是编译器在编译代码时所知道的东西[链接器可能知道,但后来就是这样]。 对于全局数组和堆上分配的数组,限制是“进程可以获得多少内存”,因此没有上限。

没有简单的方法来确定这一点。 标准提供的许多限制是为了保证只要您的代码遵循规则,就可以在“任何编译器”上编译代码。 编译并能够完成运行是两回事。

int main(){while(1); }

将永远不会运行完成 – 但它将在我所知道的每个编译器中编译,并且大多数人不会说有关于存在无限循环的事情 – 这是你做的选择。

将大型数组放在堆栈上也是您的选择。 并且很可能链接器被给予几千兆字节的堆栈,在这种情况下它会没问题 – 或者堆栈是200K,并且你不能拥有50000个整数数组……

因为语言 C不应该对可用的堆栈大小施加限制。 C在许多(许多)不同的环境中运行。 怎么可能得出一个合理的数字呢? 地狱,自动存储持续时间!=堆栈,堆栈是一个实现细节。 C, 语言 ,没有说“堆栈”。

环境决定了这个东西,这是有充分理由的。 如果某个环境通过另外的方法实现自动存储持续时间而没有这样的限制怎么办? 如果硬件出现突破并且所有突然的现代机器都不需要这样的限制怎么办?

我们应该在这样的事件中修改标准吗? 如果语言 C指定了这样的实现细节,我们将不得不这样做。

你已经回答了自己的问题; 这是由于堆栈限制。 *即使这可能不起作用:

 void foo(void) { int a; ... } 

如果...实际上是对foo的递归调用。

换句话说,这与数组无关,因为同样的问题会影响所有局部变量。 标准无法强制执行要求,因为在实践中,这将转化为无限大小堆栈的要求。


*是的,我知道C标准没有谈论堆栈。 但这就是隐式模型,因为标准实际上是当时存在的实现的forms化。