Ali*_*Ali 37 c memory-management
我是初学者C程序员,我认为情况确实如此,但如果可能的话,我会想要一些肯定.
如果它们是相同的,为什么不采取一个参数呢?
pax*_*blo 22
人们大多使用分配例程来为一定数量的项目分配空间,因此calloc()
可以很好地指定.因此,例如,如果您想要100个整数的空间或20个自己的结构:
int *pInt = calloc (100, sizeof(int));
tMyStruct *pMyStruct = calloc (20, sizeof(tMyStruct));
Run Code Online (Sandbox Code Playgroud)
这段代码实际上看起来比同等的malloc()
调用稍微"好" :
int *pInt = malloc (100 * sizeof(int));
tMyStruct *pMyStruct = malloc (20 * sizeof(tMyStruct));
Run Code Online (Sandbox Code Playgroud)
虽然,对于经验丰富的C编码员来说,没有真正的区别(当然,除了零初始化).
我不得不说我从来没有在野外使用过calloc,因为我几乎总是在创造一个struct
没有意义的地方.我更喜欢手动初始化所有字段以确保获得我想要的值.
calloc(4,6)和calloc(6,4)不一样:
在典型的32位/ 64位系统上,第一个将分配32个字节,第二个24个字节.
void *calloc(size_t nelem, size_t elsize);
Run Code Online (Sandbox Code Playgroud)
关键点是calloc必须返回内存,就像它正确对齐为数组一样.它意味着分配一个数组并按如下方式使用:
A *p = (A*)calloc(count, sizeof(A));
for (int i = 0; i < count; ++i)
{
f(&(p[i]));
// f(p + i) is also valid
}
Run Code Online (Sandbox Code Playgroud)
要么
A *p = (A*)calloc(count, sizeof(A));
for (A *q = p; q != p + count; ++q)
{
f(q);
}
Run Code Online (Sandbox Code Playgroud)
calloc应该考虑到目标系统的填充和其他操作要求来分配数组.所以在大多数32位机器上,需要将6字节结构填充到8个字节,它将分配4个8字节的批次.
第一个参数是sizeof()的calloc很可能是一个bug,应该进行调查.
calloc,其中第二个参数不是sizeof(atype)是未定义的.它充满了隐藏的假设,对港口来说很危险.
澄清: 在典型的32位/ 64位系统上,结构很可能被填充并与32位的倍数对齐.因此,在这些系统上,sizeof 不会返回6个字节.实际上,如果编译器/平台需要,则无法保证编译器不会填充并对齐到16个字节的某个倍数.
我的答案是基于你不应该对结构大小做出假设的事实.它们可以通过编译器选项或目标平台进行更改.只要确保你的第二个参数是sizeof表达式,不要做出假设.
从标准:
calloc()函数应为nelem元素数组分配未使用的空间,每个元素的大小(以字节为单位)为elsize.该空间应初始化为所有位0.
如果分配成功,则返回的指针应适当对齐,以便可以将其指定给指向任何类型对象的指针,然后用于在分配的空间中访问此类对象或此类对象的数组(直到明确释放空间为止)或重新分配).每个这样的分配都应该产生一个指向与任何其他对象不相交的对象的指针.返回的指针应指向分配空间的开始(最低字节地址).
有一个细微的区别:Calloc 可以决定仅在需要时才将内存清零,然后还有一个好处是知道元素的大小。
我无法命名任何执行此操作的实现,但它是为此考虑的。
举个例子:
一个人分配了 4GB 的内存,但系统只有 2GB:将 2GB 的零写入虚拟内存是没有意义的,因此系统可以在该内存上设置一个脏标志以在它被加载时将其归零记忆。
尽管接受了答案(我认为这是正确的),但由于对齐,似乎存在关于分配了多少字节的混淆.所以这是我的32位Linux与gcc-4.3的一点测试:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* p1 = calloc(6, 4);
char* p2 = calloc(4, 6);
char* p3 = calloc(1,1);
printf("%p, %p, %p\n", p1, p2, p3);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果是:
0x826b008, 0x826b028, 0x826b048
Run Code Online (Sandbox Code Playgroud)
这表明,无论calloc(6,4)
和calloc(4,6)
分配相同量的存储器,这是舍入到32个字节我的系统上.将数字更改为calloc(3,4)
和calloc(4,3)
将产生以下结果:
0x95d2008, 0x95d2018, 0x95d2028
Run Code Online (Sandbox Code Playgroud)
这表明当请求12并分配给程序时保留16个字节.在任何一种情况下,两者calloc(a,b)
和calloc(b,a)
调用都会对内存使用产生相同的影响.
由Jonathan Leffler添加,因为300个字符永远不够.
考虑一下这个程序,它会像一个名副其实的筛子一样泄漏内存,但它表明了一点:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int i, j, k;
for (i = 1; i < 17; i++)
for (j = 1; j < 9; j++)
for (k = 0; k < 4; k++)
printf("(%2d,%d)%d: %p\n", i, j, k, calloc(i, j));
return(0);
}
Run Code Online (Sandbox Code Playgroud)
在Windows上,在Cygwin下,这开始于分配相隔16个字节的块(实际上,第二个块在第一个块之后是24个字节,但此后,它们相隔16个字节).分配(2,7)时,块地址开始递增24个字节; 同样地,(3,4)分配16个字节的块,但是(3,5)分配24个字节的块.并且,对于记录,(4,6)和(6,4)返回指针间隔32个字节.
这只是表明存在与分配调用相关的一些开销.如果你看一下k&R中malloc()等的原型实现,你会发现块的大小存储在你有权使用的内存之前.不同的实现不同地做这些事情; 那些担心内存踩踏的人会避免将控制数据存储在用户可能造成严重破坏的地方附近.
当你调用calloc(4,6)时,你只能可靠地访问24个字节的数据.即使您的实现提供了相距32个字节的返回值,您也可能无法安全地使用超过您请求的24个字节.如果你写出你请求的边界,malloc()的调试版本将会观察到.
还有另一种方式来研究这个问题。
GNU C 库定义 calloc 如下:
void * __libc_calloc (size_t n, size_t elem_size)
{
// ... (declarations)
/* size_t is unsigned so the behavior on overflow is defined. */
bytes = n * elem_size;
#define HALF_INTERNAL_SIZE_T \
(((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2))
if (__builtin_expect ((n | elem_size) >= HALF_INTERNAL_SIZE_T, 0))
{
if (elem_size != 0 && bytes / elem_size != n)
{
__set_errno (ENOMEM);
return 0;
}
}
void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
{
sz = bytes;
mem = (*hook)(sz, RETURN_ADDRESS (0));
if (mem == 0)
return 0;
return memset (mem, 0, sz);
}
sz = bytes;
// ...more stuff, but no mention of n & elem_size anymore
}
Run Code Online (Sandbox Code Playgroud)
所以,至少在 glibc 中这两个调用确实具有相同的效果。
这是相同的。原因是因为大多数时候您想使用sizeof
运算符作为参数之一。如果传递两个参数让您烦恼,请调用malloc()
具有单个参数的函数。
归档时间: |
|
查看次数: |
6714 次 |
最近记录: |