我想声明一个非常大的数组。我发现数组的最大大小是size_t,定义为UINT_MAX
所以我写了这样的代码
int arr[UINT_MAX];
当我编译这个时,它说数组维度溢出
但是当我这样写
size_t s = UINT_MAX;
int arr[s];
它编译正确。有什么不同
第一个错误:size_t
不一定是unsigned int
,因此它的最大值可能与unsigned int
( UINT_MAX
) 不同;此外,在 C++ 中获取有关您应该使用的类型限制的信息std::numeric_limits
。
#include <limits>
size_t s=std::numeric_limits<size_t>::max();
第二个错误:你永远不会得到这么大的数组;由于size_t
需要能够表达任何对象的最大大小,它应该可能足够大以表达一个对象,该对象大到应用程序可用的整个地址空间,但尝试分配这样一个大对象将需要专用整个地址空间给它,这是不可行的;此外,您请求的int
s 数组那么大,这意味着它将是UINT_MAX*sizeof(int)
字节大,这可能是整个地址空间的大约 4 倍 - 显然是胡说八道 - 顺便说sizeof(arr)
一下,无法表达大小这样的对象,通常指针甚至无法到达该数组的顶部。编译器会检测到这些错误并阻止您这样做。
此外,我推断您正在尝试在堆栈上分配那个东西,这通常比应用程序可以使用的所有内存小得多,而且通常在那里分配大数组不是一个好主意(你应该使用堆)。
第三个错误:分配所有内存没有意义。如果你有很大的内存需求,你应该在堆上分配东西,而不是在堆栈上,并且只分配你需要与操作系统和其他应用程序一起玩的内存(如果你正在工作,最后一个考虑不适用在您是唯一运行的应用程序的嵌入式系统上)。
C++ 中的第二个片段甚至不应该工作,因为如果那个东西是在堆栈上分配的,那么你将是非标准的,因为它将是一个 VLA(在 C99 中可用,但被当前和下一个 C++ 标准强烈拒绝) . 但是,在这种情况下,分配该数组的代码是在运行时使用的(VLA 通常在维度上不固定),因此对编译器的检查并不明显(尽管我认为这件事很容易被优化器,如果 VLA 语义与常规数组没有什么不同,它可以优化掉 VLA 并尝试制作一个常规数组 => 会因我所说的相同原因而失败)。
长话短说:分配所有内存(甚至无法寻址)是没有意义的,尤其是在堆栈上。使用堆并分配你需要的东西。如果您有特殊要求,您应该研究您的操作系统提供的特殊虚拟内存功能。
您正在延迟错误。
在这两种情况下,您都要求大约 16GB* 的连续内存,这在 32 位机器上是不可能的。
你的第一次尝试是硬编码大小,你的编译器很好地提前告诉你它不会成功。
您的第二次尝试是使用大小变量,它绕过了编译器警告,但是当您尝试运行程序时它仍然会失败。
*在典型架构上
size_t s = UINT_MAX;
int arr[s];
除非您将 s 声明为 const,否则不会编译。另请注意, UINT_MAX 是数组的潜在最大大小。实际上,它不会让您声明一个大小超过几百万的数组。那是因为静态和自动,任何内存都是有限的
size_t s = UINT_MAX;
int arr[s];
表示 arr 是可变长度数组 (VLA)。我认为每个 C++ 标准都不允许这样做。如果使用编译,我会收到警告
g++ -ansi -pedantic -std=c++98
另外,考虑一下,arr
需要UINT_MAX * sizeof( int )
字节数。那是相当大!
你用的是什么编译器?在 VC++ 上,我在两种情况下都会出错(在更正s
为 be之后const
)。即使它确实编译了,它也会导致未定义的行为,因为UINT_MAX * sizeof(int)
肯定不适合您的进程的地址空间,而且整数值本身会溢出并导致错误的大小值。
对于每个无符号整数类型,最大值应由 -1 表示。例如,在 64 位系统上,以下代码
unsigned char uchar_max = -1;
printf("%u\n", uchar_max);
unsigned int uint_max = -1;
printf("%u\n", uint_max);
unsigned long ulong_max = -1;
printf("%lu\n", ulong_max);
size_t sizet_max = -1;
printf("%lu\n", sizet_max);
返回:
255
4294967295
18446744073709551615
18446744073709551615