作者:夏慕晚阳 | 来源:互联网 | 2022-12-02 19:04
在最近的一次代码审查中,有人声称
在选择系统上,calloc()
可以分配超过SIZE_MAX
总字节数,但是malloc()
有限.
我的主张是错误的,因为calloc()
为一个对象数组创建了空间 - 作为一个数组,它本身就是一个对象.没有任何物体的尺寸可以大于SIZE_MAX
.
那么我们哪个是正确的?在地址空间大于范围的(可能是假设的)系统上size_t
,calloc()
当使用产品大于SIZE_MAX
?的参数调用时,是否允许成功?
为了使它更具体:以下程序是否会以非零状态退出?
#include
#include
int main()
{
return calloc(SIZE_MAX, 2) != NULL;
}
chux - Reins..
20
calloc()总共可以分配超过SIZE_MAX吗?
作为断言"在选择系统上,calloc()
可以分配超过SIZE_MAX
总字节数,但是malloc()
有限." 来自我发布的评论,我将解释我的理由.
为size_t
size_t
是一些至少16位的无符号类型.
size_t
这是sizeof
运算符结果的无符号整数类型; C11dr§7.192
" size_t
SIZE_MAX
其实施定义的值应等于或大于......下面给出的相应值"...... ...的限制为65535§7.20.32
的sizeof
的sizeof
操作者产生其操作数的大小(以字节为单位),其可以是表达或类型的括号名称.§6.5.3.42
释放calloc
void *calloc(size_t nmemb, size_t size);
该calloc
函数为一个nmemb
对象数组分配空间,每个对象size
都是大小.§7.22.3.22
考虑一个nmemb * size
远远超过的情况SIZE_MAX
.
size_t alot = SIZE_MAX/2;
double *p = calloc(alot, sizeof *p); // assume `double` is 8 bytes.
如果calloc()
真正分配的nmemb * size
字节,如果p != NULL
是真的,这违反了什么规范?
每个元素的大小(每个对象)都是可表示的.
// Nicely reports the size of a pointer and an element.
printf("sizeof p:%zu, sizeof *p:%zu\n", sizeof p, sizeof *p);
可以访问每个元素.
// Nicely reports the value of an `element` and the address of the element
for (size_t i = 0; i
calloc()
细节
" nmemb
对象数组的空间":这当然是争论的关键点."为数组分配空间"是否需要<= SIZE_MAX
?我在C规范中没有发现任何要求这个限制的内容,因此得出结论:
calloc()
可能会分配超过SIZE_MAX
总数.
使用大量参数返回不符合规定的情况肯定是不常见的.通常这种分配超出可用内存,因此问题没有实际意义.我遇到的唯一情况是巨大的内存模型,其中16位,对象指针是32位.calloc()
NULL
size_t
1> chux - Reins..:
calloc()总共可以分配超过SIZE_MAX吗?
作为断言"在选择系统上,calloc()
可以分配超过SIZE_MAX
总字节数,但是malloc()
有限." 来自我发布的评论,我将解释我的理由.
为size_t
size_t
是一些至少16位的无符号类型.
size_t
这是sizeof
运算符结果的无符号整数类型; C11dr§7.192
" size_t
SIZE_MAX
其实施定义的值应等于或大于......下面给出的相应值"...... ...的限制为65535§7.20.32
的sizeof
的sizeof
操作者产生其操作数的大小(以字节为单位),其可以是表达或类型的括号名称.§6.5.3.42
释放calloc
void *calloc(size_t nmemb, size_t size);
该calloc
函数为一个nmemb
对象数组分配空间,每个对象size
都是大小.§7.22.3.22
考虑一个nmemb * size
远远超过的情况SIZE_MAX
.
size_t alot = SIZE_MAX/2;
double *p = calloc(alot, sizeof *p); // assume `double` is 8 bytes.
如果calloc()
真正分配的nmemb * size
字节,如果p != NULL
是真的,这违反了什么规范?
每个元素的大小(每个对象)都是可表示的.
// Nicely reports the size of a pointer and an element.
printf("sizeof p:%zu, sizeof *p:%zu\n", sizeof p, sizeof *p);
可以访问每个元素.
// Nicely reports the value of an `element` and the address of the element
for (size_t i = 0; i
calloc()
细节
" nmemb
对象数组的空间":这当然是争论的关键点."为数组分配空间"是否需要<= SIZE_MAX
?我在C规范中没有发现任何要求这个限制的内容,因此得出结论:
calloc()
可能会分配超过SIZE_MAX
总数.
使用大量参数返回不符合规定的情况肯定是不常见的.通常这种分配超出可用内存,因此问题没有实际意义.我遇到的唯一情况是巨大的内存模型,其中16位,对象指针是32位.calloc()
NULL
size_t
2> Lundin..:
SIZE_MAX
没有必要指定对象的最大大小,而是指定最大值size_t
,这不一定是同一个东西.请参阅为什么数组的最大大小"太大"?,
但很明显,传递一个更大的值而不是SIZE_MAX
一个期望一个size_t
参数的函数是没有明确定义的.所以理论上SIZE_MAX
是限制,理论上calloc
允许SIZE_MAX * SIZE_MAX
分配字节.
与malloc
/的关键calloc
是他们分配没有类型的对象.具有类型的对象具有限制,例如从不大于某个限制SIZE_MAX
.但是这些函数的结果指出的数据没有类型.它还不是一个数组.
形式上,数据没有声明的类型,但是当您在分配的数据中存储某些内容时,它会获得用于存储的有效数据访问类型(C176.5§6).
这反过来意味着可以calloc
分配比C中任何类型更多的内存,因为分配的内容不具有类型.
因此,就C标准而言,calloc(SIZE_MAX, 2)
返回与NULL不同的值是完全正确的.如何以合理的方式实际使用分配的内存,或者甚至在堆上支持如此大块内存的系统是另一个故事.