我与this answer的印象相同,UTF-8
始终保证标准足以容纳最大可能类型的给定系统。
但是,此代码无法在gcc / Mingw上编译:
size_t
错误:数组'array_t'的大小太大
我是否误解了标准中的内容?对于给定的实现,#include <stdint.h>
#include <stddef.h>
typedef uint8_t array_t [SIZE_MAX];
是否允许过大?或者这是Mingw的另一个错误?
编辑:进一步的研究表明
size_t
这恰好与
相同typedef uint8_t array_t [SIZE_MAX/2]; // does compile
typedef uint8_t array_t [SIZE_MAX/2+1]; // does not compile
所以我现在倾向于认为这是Mingw中的一个错误,因为根据有符号整数类型设置最大允许大小没有任何意义。
答案 0 :(得分:61)
限制SIZE_MAX / 2来自您实现的size_t和ptrdiff_t的定义,它们选择类型ptrdiff_t和size_t具有相同的宽度。
C标准规定 1 类型size_t是无符号的,类型为ptrdiff_t。
两个指针之间差异的结果总是 2 的类型为ptrdiff_t。这意味着,在您的实现中,对象的大小必须限制为 PTRDIFF_MAX,否则两个指针的有效差异无法在类型ptrdiff_t中表示,从而导致未定义的行为。
因此,值SIZE_MAX / 2等于值PTRDIFF_MAX。如果实现选择最大对象大小为SIZE_MAX,则必须增加类型ptrdiff_t的宽度。但是将对象的最大大小限制为SIZE_MAX / 2要容易得多,那么ptrdiff_t类型的正范围大于或等于size_t类型的正范围。
标准为此主题提供了这些 3 评论 4 。
(引自ISO / IEC 9899:201x)
1 (7.19通用定义2)
类型是
ptrdiff_t的
这是减去两个指针的结果的有符号整数类型;
为size_t
这是sizeof运算符的结果的无符号整数类型;
2 (6.5.6添加剂操作员9)
当减去两个指针时,两个指针都指向同一个数组对象的元素,
或者超过数组对象的最后一个元素;结果是差异
两个数组元素的下标。结果的大小是实现定义的,
它的类型(有符号整数类型)是标题中定义的ptrdiff_t。
如果结果在该类型的对象中无法表示,则行为未定义。
3 (K.3.4整数类型3)
极大的对象大小通常是计算对象大小的标志
不正确。例如,负数显示为非常大的正数
转换为像size_t这样的无符号类型。此外,某些实现不支持
与size_t类型可以表示的最大值一样大的对象。
4 (K.3.4整数类型4)
出于这些原因,限制要检测的对象大小的范围有时是有益的
编程错误。对于具有大地址空间的机器的实现,
建议将RSIZE_MAX定义为最大值的较小值
对象支持或(SIZE_MAX&gt;&gt;&gt; 1),即使此限制小于
一些合法但非常大的物体。针对小型机器的实现
地址空间可能希望将RSIZE_MAX定义为SIZE_MAX,这意味着没有对象大小被视为运行时约束违规。
答案 1 :(得分:16)
范围size_t
保证足以存储实现支持的最大对象的大小。反之亦然:您不能保证能够创建一个大小填充size_t
整个范围的对象。
在这种情况下,问题是:SIZE_MAX
代表什么?支持的最大对象大小?或者size_t
中可表示的最大值?答案是:它是后者,即SIZE_MAX
是(size_t) -1
。您无法保证能够创建对象SIZE_MAX
大字节。
背后的原因是除了size_t
之外,实现还必须提供ptrdiff_t
,这是(但不能保证)存储指向同一个数组对象的两个指针之间的差异。由于类型ptrdiff_t
已签名,因此实现面临以下选择:
允许大小为SIZE_MAX
的数组对象,并使ptrdiff_t
更宽而不是size_t
。它必须至少宽一点。这样的ptrdiff_t
可以容纳指向大小为SIZE_MAX
或更小的数组的两个指针之间的任何差异。
允许大小为SIZE_MAX
的数组对象,并使用与ptrdiff_t
相同宽度的size_t
。如果指针远远超过SIZE_MAX / 2
个元素,则接受指针减法可以溢出并导致未定义行为的事实。语言规范并未禁止这种方法。
使用与ptrdiff_t
相同宽度的size_t
和限制最大数组对象大小SIZE_MAX / 2
。这样的ptrdiff_t
可以容纳指向大小为SIZE_MAX / 2
或更小的数组的两个指针之间的任何差异。
您只是在处理一个决定遵循第三种方法的实现。
答案 2 :(得分:5)
它看起来非常类似于特定于实现的行为。
我在这里运行Mac OS,并且使用gcc 6.3.0,我可以使用SIZE_MAX/2
编译你的定义的最大尺寸;使用SIZE_MAX/2 + 1
它不再编译。
另一方面,女巫铿锵4.0.0最大的一个是SIZE_MAX/8
,SIZE_MAX/8 + 1
休息。
答案 3 :(得分:0)
只需从头开始推理,size_t
是一种可以容纳任何对象大小的类型。任何对象的大小都受到地址总线宽度的限制(忽略多路复用和可处理例如32位和64位代码的系统,调用&#34;代码宽度&#34;)。与MAX_INT
相关的是最大整数值,SIZE_MAX
是size_t
的最大值。因此,大小为SIZE_MAX
的对象都是可寻址的存储器。一个实现标记为错误是合理的,但是,我同意仅在分配实际对象的情况下它是错误的,无论是在堆栈上还是在全局内存中。 (无论如何,拨打malloc
的金额都会失败)