C语言 清零记忆

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2884230/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:29:27  来源:igfitidea点击:

zeroing out memory

c

提问by ant2009

gcc 4.4.4 C89

海湾合作委员会 4.4.4 C89

I am just wondering what most C programmers do when they want to zero out memory.

我只是想知道大多数 C 程序员在想要将内存清零时会做什么。

For example, I have a buffer of 1024 bytes. Sometimes I do this:

例如,我有一个 1024 字节的缓冲区。有时我这样做:

char buffer[1024] = {0};

Which will zero all bytes.

这将使所有字节归零。

However, should I declare it like this and use memset?

但是,我应该这样声明并使用memset吗?

char buffer[1024];
.
.
memset(buffer, 0, sizeof(buffer));

Is there any real reason you have to zero the memory? What is the worst that can happen by not doing it?

您是否有任何真正的理由必须将内存归零?不做的话最坏的结果是什么?

采纳答案by Tim Post

The worst that can happen? You end up (unwittingly) with a string that is not NULL terminated, or an integer that inherits whatever happened to be to the right of it after you printed to part of the buffer. Yet, unterminated strings can happen other ways, too, even if you initialized the buffer.

可能发生的最坏情况?你最终(不知不觉地)得到一个不是 NULL 终止的字符串,或者一个整数,在你打印到缓冲区的一部分后,它继承了它右边的任何东西。然而,未终止的字符串也可能以其他方式发生,即使您初始化了缓冲区。

Edit(from comments) The end of the world is also a remote possibility, depending on what you are doing.

编辑(来自评论)世界末日也是一种遥远的可能性,取决于你在做什么。

Either is undesirable. However, unless completely eschewing dynamically allocated memory, most statically allocated buffers are typically rather small, which makes memset()relatively cheap. In fact, much cheaper than most calls to calloc()for dynamic blocks, which tend to be bigger than ~2k.

两者都是不可取的。然而,除非完全避开动态分配的内存,否则大多数静态分配的缓冲区通常都相当小,这使得memset()成本相对较低。事实上,比大多数calloc()动态块调用便宜得多,动态块往往大于~2k。

c99 contains language regarding default initialization values, I can't, however, seem to make gcc -std=c99agree with that, using any kind of storage.

c99 包含有关默认初始化值的语言,但是,我似乎无法gcc -std=c99同意使用任何类型的存储。

Still, with a lot of older compilers (and compilers that aren't quite c99) still in use, I prefer to just use memset()

尽管如此,由于仍在使用许多较旧的编译器(以及不完全是 c99 的编译器),我更喜欢只使用 memset()

回答by JSB????

I vastly prefer

我非常喜欢

char buffer[1024] = { 0 };

It's shorter, easier to read, and less error-prone. Only use memseton dynamically-allocated buffers, and then prefer calloc.

它更短、更易于阅读且不易出错。仅用于memset动态分配的缓冲区,然后更喜欢calloc.

回答by spoulson

When you define char buffer[1024]without initializing, you're going to get undefined data in it. For instance, Visual C++ in debug mode will initialize with 0xcd. In Release mode, it will simply allocate the memory and not care what happens to be in that block from previous use.

当您在char buffer[1024]未初始化的情况下定义时,您将在其中获得未定义的数据。例如,调试模式下的 Visual C++ 将使用 0xcd 进行初始化。在 Release 模式下,它将简单地分配内存,而不关心之前使用的那个块中发生了什么。

Also, your examples demonstrate runtime vs. compile time initialization. If your char buffer[1024] = { 0 }is a global or static declaration, it will be stored in the binary's data segment with its initialized data, thus increasing your binary size by about 1024 bytes (in this case). If the definition is in a function, it's stored on the stack and is allocated at runtime and not stored in the binary. If you provide an initializer in this case, the initializer is stored in the binary and an equivalent of a memcpy()is done to initialize bufferat runtime.

此外,您的示例演示了运行时与编译时初始化。如果您char buffer[1024] = { 0 }是一个全局或静态声明,它将与它的初始化数据一起存储在二进制文件的数据段中,从而将您的二进制文件大小增加大约 1024 字节(在这种情况下)。如果定义在函数中,则它存储在堆栈中并在运行时分配,而不存储在二进制文件中。如果在这种情况下提供初始化程序,则初始化程序将存储在二进制文件中,并在运行时memcpy()进行等效的 a初始化buffer

Hopefully, this helps you decide which method works best for you.

希望这可以帮助您确定哪种方法最适合您。

回答by jamesdlin

In this particular case, there's not much difference. I prefer = { 0 }over memsetbecause memsetis more error-prone:

在这种特殊情况下,没有太大区别。我喜欢= { 0 }memset,因为memset是更容易出错:

  • It provides an opportunity to get the bounds wrong.
  • It provides an opportunity to mix up the arguments to memset(e.g. memset(buf, sizeof buf, 0)instead of memset(buf, 0, sizeof buf).
  • 它提供了一个错误的机会。
  • 它提供了一个混合参数的机会memset(例如memset(buf, sizeof buf, 0)代替memset(buf, 0, sizeof buf).

In general, = { 0 }is better for initializing structs too. It effectively initializes all members as if you had written = 0to initialize each. This means that pointer members are guaranteed to be initialized to the null pointer (which might not be all-bits-zero, and all-bits-zero is what you'd get if you had used memset).

一般来说,= { 0 }对于初始化structs 也更好。它有效地初始化所有成员,就好像您已编写= 0初始化每个成员一样。这意味着指针成员保证被初始化为空指针(它可能不是全位零,如果你使用了,全位零就是你得到的memset)。

On the other hand, = { 0 }can leave padding bits in a structas garbage, so it might not be appropriate if you plan to use memcmpto compare them later.

另一方面,= { 0 }可以将填充位struct作为垃圾留在 a中,因此如果您打算memcmp稍后用于比较它们可能不合适。

回答by progrmr

One of the things that can happen if you don't initialize is that you run the risk of leaking sensitive information.

如果您不初始化,可能会发生的一件事是您冒着泄露敏感信息的风险。

Uninitialized memory may have something sensitive in it from a previous use of that memory. Maybe a password or crypto key or part of a private email. Your code may later transmit that buffer or struct somewhere, or write it to disk, and if you only partially filled it the rest of it still contains those previous contents. Certain secure systems require zeroizingbuffers when an address space can contain sensitive information.

未初始化的内存中可能包含之前使用该内存的敏感内容。可能是密码或加密密钥或私人电子邮件的一部分。您的代码稍后可能会将该缓冲区或结构传输到某处,或将其写入磁盘,如果您只是部分填充它,其余部分仍包含先前的内容。当地址空间可能包含敏感信息时,某些安全系统需要缓冲区清零

回答by progrmr

I prefer using memsetto clear a chunk of memory, especially when working with strings. I want to know without a doubt that there will be a null delimiter after my string. Yes, I know you can append a \0on the end of each string and some functions do this for you, but I want no doubt that this has taken place.

我更喜欢memset用来清除一大块内存,尤其是在处理字符串时。我想毫无疑问地知道我的字符串后面会有一个空分隔符。是的,我知道您可以\0在每个字符串的末尾附加 a并且某些函数会为您执行此操作,但我想毫无疑问这已经发生了。

A function could fail when using your buffer, and the buffer remains unchanged. Would you rather have a buffer of unknown garbage, or nothing?

使用缓冲区时,函数可能会失败,并且缓冲区保持不变。你宁愿有一个未知垃圾的缓冲区,还是什么都没有?

回答by Vicky

The worst that can happen by not doing it is that you write some data in character by character and later interpret it as a string (and you didn't write a null terminator). Or you end up failing to realise a section of it was uninitialised and read it as though it were valid data. Basically: all sorts of nastiness.

不这样做可能发生的最糟糕的情况是您逐个字符地写入一些数据,然后将其解释为字符串(并且您没有写入空终止符)。或者你最终没有意识到它的一部分是未初始化的,而是把它当作有效数据来读取。基本上:各种肮脏。

Memset should be fine (provided you correct the sizeof typo :-)). I prefer that to your first example because I think it's clearer.

Memset 应该没问题(前提是您更正了大小写错字 :-))。我更喜欢你的第一个例子,因为我认为它更清楚。

For dynamically allocated memory, I use calloc rather than malloc and memset.

对于动态分配的内存,我使用 calloc 而不是 malloc 和 memset。

回答by Samir Talwar

Depends how you're filling it: if you're planning on writing to it before even potentially reading anything, then why bother? It also depends what you're going to use the buffer for: if it's going to be treated as a string, then you just need to set the first byte to \0:

取决于你如何填充它:如果你打算在甚至可能阅读任何东西之前写它,那何必呢?它还取决于您要使用缓冲区做什么:如果将其视为字符串,则只需将第一个字节设置为\0

char buffer[1024];
buffer[0] = '
char buffer[1024] = {0};
';

However, if you're using it as a byte stream, then the contents of the entire array are probably going to be relevant, so memseting the entire thing or setting it to { 0 }as in your example is a smart move.

但是,如果您将它用作字节流,则整个数组的内容可能会相关,因此memset将整个内容或设置{ 0 }为您的示例中的内容是明智之举。

回答by Edwin Buck

This post has been heavily edited to make it correct. Many thanks to Tyler McHenery for pointing out what I missed.

这篇文章已经过大量编辑以使其正确。非常感谢 Tyler McHenery 指出我遗漏的内容。

##代码##

Will set the first char in the buffer to null, and the compiler will then expand all non-initialized chars to 0 too. In such a case it seems that the differences between the two techniques boil down to whether the compiler generates more optimized code for array initialization or whether memset is optimized faster than the generated compiled code.

将缓冲区中的第一个字符设置为空,然后编译器也会将所有未初始化的字符扩展为 0。在这种情况下,这两种技术之间的差异似乎归结为编译器是否为数组初始化生成更优化的代码,或者 memset 是否比生成的编译代码优化得更快。

Previously I stated:

之前我说过:

char buffer[1024] = {0};

Will set the first char in the buffer to null. That technique is commonly used for null terminated strings, as all data past the first null is ignored by subsequent (non-buggy) functions that handle null terminated strings.

字符缓冲区[1024] = {0};

将缓冲区中的第一个字符设置为空。该技术通常用于空终止字符串,因为处理空终止字符串的后续(非错误)函数会忽略第一个空值之后的所有数据。

Which is not quite true. Sorry for the miscommunication, and thanks again for the corrections.

这并不完全正确。抱歉造成误会,再次感谢您的更正。

回答by LoudNPossiblyWrong

I also use memset(buffer, 0, sizeof(buffer));

我也使用 memset(buffer, 0, sizeof(buffer));

The risk of not using it is that there is no guarantee that the buffer you are using is completely empty, there might be garbage which may lead to unpredictable behavior.

不使用它的风险是不能保证您使用的缓冲区是完全空的,可能会有垃圾导致不可预测的行为。

Always memset-ing to 0 after malloc, is a very good practice.

在 malloc 之后始终将 memset-ing 设置为 0,这是一个很好的做法。