简体   繁体   English

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

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

In Win32 API programming it's typical to use C struct s with multiple fields.在 Win32 API 编程中,通常使用具有多个字段的 C struct 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:这可以通过以下两种方式之一实现:

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?使用哪个变体,为什么?

Those two constructs a very different in their meaning.这两个构造的含义非常不同。 The first one uses a memset function, which is intended to set a buffer of memory to certain value .第一个使用memset函数,该函数旨在将内存缓冲区设置为某个值 The second to initialize an object .第二个初始化一个对象 Let me explain it with a bit of code:让我用一些代码解释一下:

Lets assume you have a structure that has members only of POD types ("Plain Old Data" - see What are POD types in C++? )假设您有一个仅包含 POD 类型成员的结构(“Plain Old Data” - 请参阅C++ 中的 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)在这种情况下写一个POD_OnlyStruct t = {}POD_OnlyStruct t; memset(&t, 0, sizeof t) POD_OnlyStruct t; memset(&t, 0, sizeof t) doesn't make much difference, as the only difference we have here is the alignment bytes being set to zero-value in case of memset used. POD_OnlyStruct t; memset(&t, 0, sizeof t)没有太大区别,因为我们这里唯一的区别是在使用memset情况下对齐字节设置为零值。 Since you don't have access to those bytes normally, there's no difference for you.由于您通常无法访问这些字节,因此对您来说没有区别。

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 memset on it will lead to crash.在这种情况下,使用像TestStruct t = {}这样的表达式是好的,在它上面使用memset会导致崩溃。 Here's what happens if you use memset - an object of type TestStruct is created, thus creating an object of type std::string , since it's a member of our structure.如果您使用memset会发生以下情况 - 创建了一个TestStruct类型的对象,从而创建了一个std::string类型的对象,因为它是我们结构的成员。 Next, memset sets the memory where the object b was located to certain value, say zero.接下来, memset将对象b所在的内存设置为某个值,比如零。 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 b you'll see a crash, as all of that object's internal structures were ruined by the memset .现在,一旦我们的 TestStruct 对象超出范围,它将被销毁,当轮到它的成员std::string b您将看到崩溃,因为该对象的所有内部结构都被memset破坏了。

So, the reality is, those things are very different , and although you sometimes need to memset a 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 memset on objects only if it is required, and use the default initialization x = {} in all other cases.我的投票 -只有在需要时才在对象上使用memset ,并在所有其他情况下使用默认初始化x = {}

Depending on the structure members, the two variants are not necessarily equivalent.根据结构成员的不同,这两种变体不一定等效。 memset will set the structure to all-bits-zero whereas value initialization will initialize all members to the value zero. memset会将结构设置为所有位为零,而值初始化会将所有成员初始化为零值。 The C standard guarantees these to be the same only for integral types, not for floating-point values or pointers. C 标准保证这些仅对于整数类型是相同的,而不是对于浮点值或指针。

Also, some APIs require that the structure really be set to all-bits-zero.此外,某些 API 要求将结构真正设置为所有位为零。 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.例如,伯克利套接字 API 以多态方式使用结构,重要的是将整个结构真正设置为零,而不仅仅是明显的值。 The API documentation should say whether the structure really needs to be all-bits-zero, but it might be deficient. 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, memset is 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是唯一的选择(当然,除了手动将每个成员初始化为零之外,但通常不会这样做,尤其是对于大型结构)。

If your struct contains things like :如果您的结构包含以下内容:

int a;
char b;
int c;

Then bytes of padding will be inserted between "b" and "c".然后将在“b”和“c”之间插入填充字节。 memset() will zero those, the other way will not, so there will be 3 bytes of garbage (if your ints are 32 bits). memset() 会将它们归零,反之则不会,因此将有 3 个字节的垃圾(如果您的整数是 32 位)。 If you intend to use your struct to read/write from a file, this might be important.如果您打算使用结构从文件中读/写,这可能很重要。

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 memset to zero out the struct after it has been used though.不过,您可能会依赖memset在使用后将结构归零。

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 肯定不会

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. memset() 在运行时完成。
Also using memset() is suspect if the struct is not POD.如果结构不是 POD,则使用 memset() 也是可疑的。
Does not correctly initialize (to zero) non int types.未正确初始化(为零)非 int 类型。

In some compilers STRUCT theStruct = {};在某些编译器中, STRUCT theStruct = {}; would translate to memset( &theStruct, 0, sizeof( STRUCT ) );将转换为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.一些 C 函数已经链接到执行运行时设置,因此编译器可以使用这些库函数,如 memset/memcpy。

If there are lots of pointer members and you are likely to add more in the future, it can help to use memset.如果有很多指针成员并且您将来可能会添加更多成员,则使用 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.结合适当的assert(struct->member)调用,您可以避免因尝试遵从您忘记初始化的坏指针而导致的随机崩溃。 But if you're not as forgetful as me, then member-initialization is probably the best!但如果你不像我那么健忘,那么成员初始化可能是最好的!

However , if your struct is being used as part of a public API, you should get client code to use memset as a requirement.但是,如果您的结构被用作公共 API 的一部分,您应该让客户端代码使用 memset 作为要求。 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.这有助于未来验证,因为您可以添加新成员,并且客户端代码将在 memset 调用中自动将它们清空,而不是将它们留在(可能危险的)未初始化状态。 This is what you do when working with socket structures for example.例如,这就是您在使用套接字结构时所做的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 值初始化:默认初始化还是零初始化? - Value initialization: default initialization or zero initialization? 哪个更快/首选:memset 或 for 循环将双精度数组归零? - Which is faster/preferred: memset or for loop to zero out an array of doubles? memset 与零长度参数一起使用:忽略还是小心? - memset used with zero length parameter: ignore or watch out? memset或bzero保证结构中的字段指针会被清零吗? - do memset or bzero guarantee that a field pointer in a struct will be nulled out? 有什么理由更喜欢 memset/ZeroMemory 而不是 WinAPI 结构的值初始化? - Any reason to prefer memset/ZeroMemory to value initialization for WinAPI structs? 嵌套结构的零初始化 - 编译器错误? - Zero initialization of nested struct - compiler bug? 用于在C ++中初始化的memset - memset for initialization in C++ 在具有默认非平凡构造函数的结构上使用值初始化时,结构标量成员是否被零初始化 - Are struct scalar members zero-initialized when using value-initialization on a struct with a default non-trivial-constructor 使用C ++中的memset初始化具有不同值的struct数组元素 - initialize struct array element with different value using memset in c++ 默认值和零初始化混乱 - Default, value and zero initialization mess
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM