calloc——内存清零的用处
将内存清零(即 calloc()
相对于 malloc()
)有什么优点?无论如何,您不会将值更改为其他值吗?
What is the advantage of zeroing out memory (i.e. calloc()
over malloc()
)? Won't you change the value to something else anyways?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
有两个阵营:一个阵营认为在声明变量时对其进行初始化有助于发现错误。这个阵营的人确保他们声明的所有内容都已初始化。他们将指针初始化为 NULL,将 int 初始化为 0,等等。这个想法是一切都是确定的,当他们看到一个 NULL 指针时在调试器中,他们立即知道它没有正确设置。它还可以帮助您的程序在测试期间因 NULL 指针取消引用而崩溃,而不是在生产运行中神秘地崩溃。
另一个阵营则表示,在声明时初始化变量会使调试变得更加困难,因为现在编译器无法警告您“未经设置而使用的变量”。
不告诉你我的个人偏好1:如果你属于第一阵营,你会想要
calloc()
而不是malloc()
。如果您属于第二个阵营(显然您就是这样),那么您更喜欢malloc()
而不是calloc()
。现在有两个例外:
calloc()
而是使用malloc()
因为您正在初始化浮点数或指针,并且您知道所有位为零并不一定意味着它们的0
。或者,您不想要额外的开销。calloc()
。例如,如果您想要计算n
乘m
动态分配的int
数据的按行总和。1 你可以在 SO 上看到我对许多问题的回答,看看我属于哪个阵营:-)。
There are two camps: one says that initializing variables when they are declared helps find bugs. The people in this camp make sure everything they declare is initialized. They initialize pointers to
NULL
,int
s to 0, etc. The idea is that everything is determinate, and when they see aNULL
-pointer in a debugger, they immediately know it wasn't set properly. It can also help your program crash during testing because ofNULL
-pointer dereferencing rather than mysteriously crashing in production runs.The other camp says that initializing variables at declaration makes things harder to debug, because now a compiler can't warn you about variables "used without being set".
Without telling you my personal preference1: if you belong to the first camp, you would want to
calloc()
instead ofmalloc()
. If you belong to the second camp (which apparently you do) then you prefermalloc()
overcalloc()
.Now there are two exceptions:
calloc()
butmalloc()
because you are initializing floating-point numbers or pointers, and you know that all bits zero doesn't necessarily mean0
for them. Or, you don't want the extra overhead.calloc()
when you are allocating some data and want it to be all zeroes. For example, if you want to calculate the row-wise sum of ann
bym
dynamically allocatedint
data.1 You can see my answers to many of the questions here on SO to see which camp I belong to :-).
调用
结构:它们被初始化为 NULL。在我很久以前开发的实时过程控制系统中,我们决定让上电逻辑将所有 RAM 初始化为 0xCC,即 8086 的中断 3 指令。如果处理器以某种方式执行未初始化的内存,这将导致处理器进入监视器(原始调试器)。 (毫无帮助的是,8086 愉快地执行包含零的内存,因为它们是
add [bx+si],al
指令。即使是 32 位模式也会导致它们是add [ax],al
代码>指令。)我不记得我们是否发现过失控程序,但与0xCC对应的各种值:52,428(无符号16位),-19,660(有符号16位),-107374176(32位浮点数) )和-9.25596313493e+61(64位浮点)出现在很多意想不到的地方。此外,一些期望字符为 7 位 ASCII 的代码(即错误)在尝试处理 0xCC 时提醒我们它的存在。
calloc
ing a structure with pointers: they are initialized to NULL.In a realtime process control system I worked on long ago, we settled on having the power-on logic initialize all of RAM to 0xCC, the 8086's
interrupt 3
instruction. This would cause the processor to enter the monitor (a primitive debugger) if it somehow executed uninitialized memory. (Unhelpfully, the 8086 merrily executes memory containing zeros since they areadd [bx+si],al
instructions. Even 32-bit mode causes them to beadd [ax],al
instructions.)I don't recall if we ever found a runaway program, but the values corresponding to 0xCC in various values: 52,428 (unsigned 16 bit), -19,660 (signed 16 bits), -107374176 (32-bit float), and -9.25596313493e+61 (64-bit float) popped up in a lot of unexpected places. Also, some code expecting characters to be 7 bit ASCII—that is, a bug—alerted us to its presence when it tried to process 0xCC.
假设您想要编写计数排序实现,或者深度优先搜索图并跟踪访问的顶点。您将在算法运行时更新您的内存(而不是只分配一次值)。您需要在开始时将其初始化为零。如果您没有
calloc
,则必须手动检查它并在算法开始时将其初始化为零。calloc
可以为您更有效地完成此操作。Assume you want to write a counting sort implementation, or depth first search a graph and keep track of visited vertices. You'll update your memory as the algorithm runs (rather than assigning a value just once). You need to initialize it to zero at the beginning. If you didn't have
calloc
, you'd have to manually go through it and initialize it to zero at the beginning of your algorithm.calloc
can potentially do this more efficiently for you.很高兴知道您分配的任何内容都被初始化为零。许多错误都是由使用未初始化内存的代码引起的。另外,结构/类中的某些默认值可能为零,因此您无需更改 malloc 之后的所有值。
例如,使用 malloc 分配一个包含一些指针的结构。 NULL 检查并不总是有效,除非将其设置为 NULL。如果您 calloc,则不必对指针值执行额外的初始化步骤。
It's good to know that whatever you're allocating is initialized to zero. Many bugs have come about from code that uses uninitialized memory. Plus, some default values in structs / classes might be fine as zero so you don't need to change all values after the malloc.
For instance, allocate a struct that has some pointers in it w/ malloc. NULL checks aren't always going to work unless they are set to NULL. If you calloc, you don't have to do the extra initialization steps for pointer values.
除了初始化变量的好处之外,calloc 还有助于跟踪错误。
如果您不小心使用了一些分配的内存而没有正确初始化它,应用程序总是会以同样的方式失败。例如,来自空指针的访问冲突。使用 malloc 时,内存具有随机值,这可能会导致程序以随机方式失败。
随机故障很难追踪,而 calloc 可以帮助避免这些情况。
In addition to the benefits of initializing variables calloc also helps track down bugs.
If you accidently use a bit of the allocated memory without properly initializing it the application will always fail the same way. For example with a access violation from a null pointer. With malloc the memory has random values and this can cause the program to fail in random ways.
Random failures are very hard to track down and calloc helps avoid those.
首先,你不能调用指针,至少如果你想遵循标准 C,则不能。
其次,当你用全零破坏成员时,错误就会被掩盖。更好的做法是使用 malloc 的调试版本,将内存初始化为始终会崩溃的内容,例如 0xCDCCDCD。
然后,当您看到访问失败时,您会立即知道问题所在。
拥有免调试功能也是有益的,该功能将以不同的模式鞭打内存,以便那些在释放内存后接触内存的人会得到意想不到的惊喜。
在嵌入式系统上工作时,仅仅为了“确定”而进行调用通常不是一种选择。您通常会一次性分配和填充,因此 calloc 只是您双重触摸内存。
First of all you cannot calloc pointers, at least not if you want to follow standard C.
Second, bugs just becoming masked when you clobber the member with all zeros. It is much better practice to have a debug version of malloc that initialises the memory to something that will always crash, such as 0xCDCDCDCD.
Then when you see an Access voilation you know the problem straight away.
It is also beneficial to have debug free function that will whip thje memory with a different pattern so those who touch the memory after it is freed get an unexpected surprise.
Working on an embedded system, callocing just to "be sure" is usually not an option. You typically allocate and populate in one go so calloc just mens you are double touching memory.
没有人涉及性能方面,所以我想我必须这样做。如果您需要编写一个非常快的程序,并且带有“以防万一”的集成内存集,那么 malloc 并不是一个好方法。无论 memset 有多快,它总是太慢。有时您必须初始化向量或数组,因此真正的问题是控制时钟周期(即不浪费它们)。我曾经听过一句话“你永远不应该意外地放弃性能”,这意味着从性能的角度来看,你必须始终知道为什么选择以这种或另一种方式实现代码(优点和缺点是什么以及如何权衡它们)在具体情况下彼此)。
如果您有一个将填充字符串的缓冲区,那么在填充字符串之前对其进行初始化可能是“很好”,但大多数人都会同意这完全是时钟周期的浪费。如果您正在编写一个新的 str* 函数,您可能需要 - 出于调试目的 - 用通常不应该出现的值填充缓冲区,但在分发时该值将被删除。
正如其他人提到的,如果正在访问未初始化的变量,编译器会发出警告,因此据我所知,底线是确实没有理由初始化“以防万一”。
No one has touched on the aspect of performance so I guess I'll have to. If you need to write a very fast program malloc with a "just in case" integrated memset is not a good way to go. It doesn't matter how fast the memset is, it will always be too slow. Sometimes you must initialize a vector or an array so the real issue is having control of your clock cycles (i e not wasting them). I heard a quote once "you should never give up performance accidentally" which means that from a performance standpoint you must always know why you have chosen to implement code in one way or another (what the pros and cons are and how they are weighed against each other in the specific case).
If you have a buffer that will be filled with a string it might be "nice to have" to initialize it before the string is filled in but most will agree it's a complete waste of clock cycles. If you're writing a new str* function you might want to - for debugging purposes - fill the buffer with a value that typically shouldn't appear but this will have been removed come distribution time.
As others have mentioned the compiler will warn if an uninitialized variable is being accessed so as I see it the bottom line is that there really is no excuse for initializing "just in case."