C 为什么数组的最大大小是;太大了;?
我的印象是,C 为什么数组的最大大小是;太大了;?,c,gcc,mingw,size-t,stdint,C,Gcc,Mingw,Size T,Stdint,我的印象是,size\u t始终由标准保证足够大,以容纳给定系统的最大可能类型 但是,此代码无法在gcc/Mingw上编译: #include <stdint.h> #include <stddef.h> typedef uint8_t array_t [SIZE_MAX]; 这恰好与 #include <limits.h> typedef uint8_t array_t [LLONG_MAX]; // does compile ty
size\u t
始终由标准保证足够大,以容纳给定系统的最大可能类型
但是,此代码无法在gcc/Mingw上编译:
#include <stdint.h>
#include <stddef.h>
typedef uint8_t array_t [SIZE_MAX];
这恰好与
#include <limits.h>
typedef uint8_t array_t [LLONG_MAX]; // does compile
typedef uint8_t array_t [LLONG_MAX+(size_t)1]; // does not compile
#包括
typedef uint8_t数组[LLONG_MAX];//编译
typedef uint8_t数组[LLONG_MAX+(size_t)1];//不编译
因此,我现在倾向于认为这是Mingw中的一个缺陷,因为基于有符号整数类型设置允许的最大大小没有任何意义。仅从零开始推理,
size\u t
是一种可以容纳任何对象大小的类型。任何对象的大小都受到地址总线宽度的限制(忽略多路复用和可以处理例如32位和64位代码的系统,称之为“代码宽度”)。不知道MAX\u INT
是最大整数值,SIZE\u MAX
是SIZE\u t
的最大值。因此,大小为size\u MAX
的对象都是可寻址内存。实现将其标记为错误是合理的,但是,我同意只有在实际对象被分配的情况下才是错误,无论是在堆栈上还是在全局内存中。(无论如何,调用malloc
获取该金额都将失败)它看起来非常像特定于实现的行为
我在这里运行Mac OS,使用gcc 6.3.0,我可以编译您定义的最大大小是size_MAX/2
;使用SIZE\u MAX/2+1
它不再编译
另一方面,witch clang 4.0.0最大的一个是
SIZE\u MAX/8
,并且SIZE\u MAX/8+1
中断。限制大小\u MAX/2来自于实现中的SIZE\u t和ptrdiff\u t的定义,它们选择类型ptrdiff\u t和SIZE\u t具有相同的宽度
C标准要求1类型大小为无符号,类型ptrdiff为有符号
两个指针之间的差异结果将始终具有类型ptrdiff_t。这意味着,在您的实现中,对象的大小必须限制为
PTRDIFF_MAX,否则在类型PTRDIFF_t中无法表示两个指针的有效差异,从而导致未定义的行为
因此,值SIZE_MAX/2等于值PTRDIFF_MAX。如果实现选择将最大对象大小设置为SIZE_MAX,则必须增加类型PTRDIFF_t的宽度。但是,将对象的最大大小限制为size_MAX/2要容易得多,然后让类型ptrdiff_t的正范围大于或等于类型size_t的正范围
《标准》提供了关于该主题的3条评论
(引自ISO/IEC 9899:201x) 1(7.19通用定义2)
类型为
ptrdiff\u t
它是减去两个指针的结果的有符号整数类型
大小\u t
它是sizeof运算符结果的无符号整数类型 2(6.5.6加法运算符9)
减去两个指针时,两个指针都应指向同一数组对象的元素, 或超过数组对象最后一个元素一次;结果是两个参数的差异 两个数组元素的下标。结果的大小由实现定义, 并且其类型(有符号整数类型)是在头中定义的ptrdiff_t。 如果结果不能在该类型的对象中表示,则行为是未定义的 3(K.3.4整数类型3)
超大的对象大小通常是计算对象大小的标志 不对。例如,负数在以下情况下显示为非常大的正数: 已转换为大小\u t之类的无符号类型。此外,一些实现不支持 与类型大小\u t表示的最大值一样大的对象 4(K.3.4整数类型4)
出于这些原因,限制要检测的对象大小范围有时是有益的 编程错误。对于针对具有大地址空间的计算机的实现, 建议将RSIZE_MAX定义为最大尺寸中的较小值 支持的对象或(大小\u MAX>>1),即使此限制小于 一些合法但非常大的物体。针对小型计算机的实现
地址空间可能希望将RSIZE_MAX定义为SIZE_MAX,这意味着不存在被视为违反运行时约束的对象大小。保证
SIZE_t
的范围足以存储实现支持的最大对象的大小。反之则不然:不能保证您能够创建一个对象,该对象的大小可以填充整个size\u t
范围
在这种情况下,问题是:SIZE\u MAX
代表什么?支持的最大对象大小?或可在大小\u t
中表示的最大值?答案是:它是后者,即SIZE\u MAX
是(SIZE\u t)-1
。不能保证您能够创建大字节的对象SIZE\u MAX
bytes
这背后的原因是,除了size\u t
,实现还必须提供ptrdiff\u t
,其目的是(但不保证)存储指向同一数组对象的两个指针之间的差异。由于类型ptrdiff\u t
已签名,因此实现面临以下选择:
size\u MAX
的数组对象,并使ptrdiff\u t
比size\u t
宽。它必须至少宽一点。这样的ptrdiff\u t
可以容纳指向大小size\u MAX
或更小数组的两个指针之间的任何差异size\u MAX
的数组对象,并使用与size\u t
宽度相同的ptrdiff\u t
。接受p
#include <limits.h>
typedef uint8_t array_t [LLONG_MAX]; // does compile
typedef uint8_t array_t [LLONG_MAX+(size_t)1]; // does not compile