calloc——内存清零的用处

发布于 2024-08-21 13:17:07 字数 87 浏览 5 评论 0原文

将内存清零(即 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

我一向站在原地 2024-08-28 13:17:07

有两个阵营:一个阵营认为在声明变量时对其进行初始化有助于发现错误。这个阵营的人确保他们声明的所有内容都已初始化。他们将指针初始化为 NULL,将 int 初始化为 0,等等。这个想法是一切都是确定的,当他们看到一个 NULL 指针时在调试器中,他们立即知道它没有正确设置。它还可以帮助您的程序在测试期间因 NULL 指针取消引用而崩溃,而不是在生产运行中神秘地崩溃。

另一个阵营则表示,在声明时初始化变量会使调试变得更加困难,因为现在编译器无法警告您“未经设置而使用的变量”。

不告诉你我的个人偏好1:如果你属于第一阵营,你会想要calloc()而不是malloc()。如果您属于第二个阵营(显然就是这样),那么您更喜欢 malloc() 而不是 calloc()

现在有两个例外:

  • 如果您属于“初始化所有内容”阵营,那么您不会使用 calloc() 而是使用 malloc() 因为您正在初始化浮点数或指针,并且您知道所有位为零并不一定意味着它们的0。或者,您不想要额外的开销。
  • 如果您属于“需要时设置”阵营,那么当您分配一些数据并希望其全部为零时,您可能需要calloc()。例如,如果您想要计算 nm 动态分配的 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, ints to 0, etc. The idea is that everything is determinate, and when they see a NULL-pointer in a debugger, they immediately know it wasn't set properly. It can also help your program crash during testing because of NULL-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 of malloc(). If you belong to the second camp (which apparently you do) then you prefer malloc() over calloc().

Now there are two exceptions:

  • If you belong to the "initialize everything" camp, you don't calloc() but malloc() because you are initializing floating-point numbers or pointers, and you know that all bits zero doesn't necessarily mean 0 for them. Or, you don't want the extra overhead.
  • If you belong to the "set when you need to" camp, you may want to 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 an n by m dynamically allocated int data.

1 You can see my answers to many of the questions here on SO to see which camp I belong to :-).

人生百味 2024-08-28 13:17:07
  1. 通过了解已有的价值,程序员可以采取一些捷径并进行某些优化。最常见的是,使用指针调用结构:它们被初始化为 NULL。
  2. 如果程序员忘记初始化分配中的某些内容怎么办?零是一个很好的默认值,而不是随机的东西。

在我很久以前开发的实时过程控制系统中,我们决定让上电逻辑将所有 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 时提醒我们它的存在。

  1. By knowing what value is already there, a programmer can take some shortcuts and make certain optimizations. Most frequently, callocing a structure with pointers: they are initialized to NULL.
  2. What if the programmer forgot to initialize something in the allocation? Instead of random stuff, zero is a great default value.

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 are add [bx+si],al instructions. Even 32-bit mode causes them to be add [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.

离鸿 2024-08-28 13:17:07

假设您想要编写计数排序实现,或者深度优先搜索图并跟踪访问的顶点。您将在算法运行时更新您的内存(而不是只分配一次值)。您需要在开始时将其初始化为零。如果您没有 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.

苍暮颜 2024-08-28 13:17:07

很高兴知道您分配的任何内容都被初始化为零。许多错误都是由使用未初始化内存的代码引起的。另外,结构/类中的某些默认值可能为零,因此您无需更改 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.

你的呼吸 2024-08-28 13:17:07

除了初始化变量的好处之外,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.

£烟消云散 2024-08-28 13:17:07

没有人涉及性能方面,所以我想我必须这样做。如果您需要编写一个非常快的程序,并且带有“以防万一”的集成内存集,那么 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."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文