C++ memset() 或值初始化以将结构归零?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1998752/
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-08-27 21:48:24  来源:igfitidea点击:

memset() or value initialization to zero out a struct?

c++cvisual-c++structinitialization

提问by sharptooth

In Win32 API programming it's typical to use C structs with multiple fields. Usually only a couple of them have meaningful values and all others have to be zeroed out. This can be achieved in either of the two ways:

在 Win32 API 编程中,通常使用struct具有多个字段的C 。通常只有其中几个具有有意义的值,而所有其他值都必须归零。这可以通过以下两种方式之一实现:

STRUCT theStruct;
memset( &theStruct, 0, sizeof( STRUCT ) );

or

或者

STRUCT theStruct = {};

The second variant looks cleaner - it's a one-liner, it doesn't have any parameters that could be mistyped and lead to an error being planted.

第二个变体看起来更简洁——它是单行的,它没有任何可能输入错误并导致植入错误的参数。

Does it have any drawbacks compared to the first variant? Which variant to use and why?

与第一个变体相比,它有什么缺点吗?使用哪个变体,为什么?

回答by Dmitry

Those two constructs a verydifferent in their meaning. The first one uses a memsetfunction, which is intended to set a buffer of memory to certain value. The second to initialize an object. Let me explain it with a bit of code:

这两个构造的含义非常不同。第一个使用一个memset函数,该函数旨在将内存缓冲区设置为某个值。第二个初始化一个对象。让我用一些代码解释一下:

Lets assume you have a structure that has members only of POD types

让我们假设您有一个结构,其中只有 POD 类型的成员

struct POD_OnlyStruct
{
    int a;
    char b;
};

POD_OnlyStruct t = {};  // OK

POD_OnlyStruct t;
memset(&t, 0, sizeof t);  // OK as well

In this case writing a POD_OnlyStruct t = {}or POD_OnlyStruct t; memset(&t, 0, sizeof t)doesn't make much difference, as the only difference we have here is the alignmentbytes being set to zero-value in case of memsetused. Since you don't have access to those bytes normally, there's no difference for you.

在这种情况下,写 a POD_OnlyStruct t = {}orPOD_OnlyStruct t; memset(&t, 0, sizeof t)没有太大区别,因为我们在这里唯一的区别是对齐字节在使用的情况下设置为零值memset。由于您通常无法访问这些字节,因此对您来说没有区别。

On the other hand, since you've tagged your question as C++, let's try another example, with member types different from POD:

另一方面,由于您已将问题标记为 C++,让我们尝试另一个示例,其成员类型与 POD 不同

struct TestStruct
{
    int a;
    std::string b;
};

TestStruct t = {};  // OK

{
    TestStruct t1;
    memset(&t1, 0, sizeof t1);  // ruins member 'b' of our struct
}  // Application crashes here

In this case using an expression like TestStruct t = {}is good, and using a memseton it will lead to crash. Here's what happens if you use memset- an object of type TestStructis created, thus creating an object of type std::string, since it's a member of our structure. Next, memsetsets the memory where the object bwas located to certain value, say zero. Now, once our TestStruct object goes out of scope, it is going to be destroyed and when the turn comes to it's member std::string byou'll see a crash, as all of that object's internal structures were ruined by the memset.

在这种情况下,使用 like 表达式TestStruct t = {}是好的,而memset在其上使用 a会导致崩溃。下面是如果你使用会发生什么memset-TestStruct创建一个类型的对象,从而创建一个类型的对象std::string,因为它是我们结构的成员。接下来,memset将对象所在的内存b设置为某个值,比如零。现在,一旦我们的 TestStruct 对象超出范围,它将被销毁,当轮到它的成员时,std::string b您将看到崩溃,因为该对象的所有内部结构都被memset.

So, the reality is, those things are very different, and although you sometimes need to memseta whole structure to zeroes in certain cases, it's always important to make sure you understand what you're doing, and not make a mistake as in our second example.

所以,现实是,这些事情是非常不同的,尽管有时memset在某些情况下您需要将整个结构归零,但确保您了解自己在做什么总是很重要的,而不是像我们第二次那样犯错误例子。

My vote - use memseton objects onlyif it is required, and use the defaultinitialization x = {}in all other cases.

我的投票 -在需要时memset用于对象,并在所有其他情况下使用默认初始化。x = {}

回答by JaakkoK

Depending on the structure members, the two variants are not necessarily equivalent. memsetwill set the structure to all-bits-zero whereas value initialization will initialize all members to the value zero. The C standard guarantees these to be the same only for integral types, not for floating-point values or pointers.

根据结构成员的不同,这两种变体不一定等效。memset会将结构设置为所有位为零,而值初始化会将所有成员初始化为零值。C 标准保证这些仅对于整数类型是相同的,而不是对于浮点值或指针。

Also, some APIs require that the structure really be set to all-bits-zero. For instance, the Berkeley socket API uses structures polymorphically, and there it is important to really set the whole structure to zero, not just the values that are apparent. The API documentation should say whether the structure really needs to be all-bits-zero, but it might be deficient.

此外,某些 API 要求将结构真正设置为所有位为零。例如,伯克利套接字 API 以多态方式使用结构,重要的是将整个结构真正设置为零,而不仅仅是明显的值。API 文档应该说明结构是否真的需要全部为零,但它可能有缺陷。

But if neither of these, or a similar case, applies, then it's up to you. I would, when defining the structure, prefer value initialization, as that communicates the intent more clearly. Of course, if you need to zeroize an existing structure, memsetis the only choice (well, apart from initializing each member to zero by hand, but that wouldn't normally be done, especially for large structures).

但是,如果这些或类似的情况都不适用,那么这取决于您。在定义结构时,我更喜欢值初始化,因为它可以更清楚地传达意图。当然,如果您需要将现有结构归零,这memset是唯一的选择(好吧,除了手动将每个成员初始化为零之外,但通常不会这样做,尤其是对于大型结构)。

回答by peufeu

If your struct contains things like :

如果您的结构包含以下内容:

int a;
char b;
int c;

Then bytes of padding will be inserted between "b" and "c". memset() will zero those, the other way will not, so there will be 3 bytes of garbage (if your ints are 32 bits). If you intend to use your struct to read/write from a file, this might be important.

然后将在“b”和“c”之间插入填充字节。memset() 会将它们归零,反之则不会,因此将有 3 个字节的垃圾(如果您的整数是 32 位)。如果您打算使用结构从文件中读/写,这可能很重要。

回答by Gregory Pakosz

I would use value initialization because it looks clean and less error prone as you mentioned. I don't see any drawback in doing it.

我会使用值初始化,因为它看起来很干净,而且不像你提到的那样容易出错。我认为这样做没有任何缺点。

You might rely on memsetto zero out the struct after it has been used though.

不过,您可能需要在memset使用后将结构归零。

回答by Toad

not that it's common, but I guess the second way also has the benefit of initializing floats to zero. While doing a memset would certainly not

并不是说它很常见,但我想第二种方法也有将浮点数初始化为零的好处。虽然做 memset 肯定不会

回答by Martin York

The value initialization because it can be done at compile time.
Also it correctly 0 initializes all POD types.

值的初始化因为它可以在编译时完成。
它也正确 0 初始化所有 POD 类型。

The memset() is done at runtime.
Also using memset() is suspect if the struct is not POD.
Does not correctly initialize (to zero) non int types.

memset() 在运行时完成。
如果结构不是 POD,则使用 memset() 也是可疑的。
未正确初始化(为零)非 int 类型。

回答by Gerhard

In some compilers STRUCT theStruct = {};would translate to memset( &theStruct, 0, sizeof( STRUCT ) );in the executable. Some C functions are already linked in to do runtime setup so the compiler have these library functions like memset/memcpy available to use.

在某些编译器中STRUCT theStruct = {};会转换为memset( &theStruct, 0, sizeof( STRUCT ) );可执行文件。一些 C 函数已经链接到执行运行时设置,因此编译器可以使用这些库函数,如 memset/memcpy。

回答by Mike Weller

If there are lots of pointer members and you are likely to add more in the future, it can help to use memset. Combined with appropriate assert(struct->member)calls you can avoid random crashes from trying to deference a bad pointer that you forgot to initialize. But if you're not as forgetful as me, then member-initialization is probably the best!

如果有很多指针成员并且您将来可能会添加更多成员,则使用 memset 会有所帮助。结合适当的assert(struct->member)调用,您可以避免因尝试遵从您忘记初始化的错误指针而导致的随机崩溃。但如果你不像我那么健忘,那么成员初始化可能是最好的!

However, if your struct is being used as part of a public API, you should get client code to use memset as a requirement. This helps with future proofing, because you can add new members and the client code will automatically NULL them out in the memset call, rather than leaving them in a (possibly dangerous) uninitialized state. This is what you do when working with socket structures for example.

但是,如果您的结构被用作公共 API 的一部分,您应该让客户端代码使用 memset 作为要求。这有助于未来验证,因为您可以添加新成员,并且客户端代码将在 memset 调用中自动将它们清空,而不是将它们留在(可能危险的)未初始化状态。例如,这就是您在使用套接字结构时所做的。