21

In Win32 programming a handful of POD structs is used. Those structs often need to be zeroed out before usage.

This can be done by calling memset()/ZeroMemory()

STRUCT theStruct;
ZeroMemory( &theStruct, sizeof( theStruct ) );

or by value initialization:

STRUCT theStruct = {};

Although the two variants above are not equivalent in general:

  • treat padding differently
  • treat non-POD member variables differently

in case of POD structs used in Win32 they look equivalent.

Are there any cases when memset()/ZeroMemory() should be used instead of value initialization with Win32 POD structs?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Duplicate of http://stackoverflow.com/q/1998752/471164 – vitaut Jul 19 '12 at 21:12
  • @vitaut: That's not a complete dupe - this question is asking for specific cases when the first approach should be preferred. – sharptooth Jul 20 '12 at 07:26
  • Related: http://stackoverflow.com/questions/3038302/why-do-zeromemory-etc-exist-when-there-are-memset-etc-already – Amro Aug 14 '13 at 22:31
  • An excellent [Post about ZeroMemory by Raymond Chen](http://blogs.msdn.com/b/oldnewthing/archive/2005/06/28/433341.aspx) - **No, it doesn't answer the question** but it's a good read. – gideon Apr 18 '15 at 16:11

7 Answers7

29

I always use:

STRUCT theStruct = {}; // for C++, in C use {0}

It's shorter, standard, therefore more elegant, and I don't really care about the theoretical differences. We are talking about code for a concrete OS here.

Another advantage is you can also immediately set the struct size in the first member like this:

STRUCT theStruct = {sizeof(STRUCT)}; 

Many Win32 structs require you to set the size in a first member.

11

In Win32, ZeroMemory is just a Macro around RtlZeroRemory, which is a macro to memset. So, I don't think it makes a difference.

WinBase.h:

\#define ZeroMemory RtlZeroMemory"

WinNT.h:

\#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
Littm
  • 4,923
  • 4
  • 30
  • 38
Dante
  • 141
  • 1
  • 5
5

If your code will serve as an example to countless Visual Basic developers who are likely to not notice or understand the C++ = {} construct, ZeroMemory is a good way to make the C++ code look more like pseudocode and minimize the incidence of subtle, hair-ripping initialization bugs.

That's the concern that the MSDN article authors faced, which then explains why ZeroMemory shows up in so much code (even C++ code).

On the other hand, if the purpose of your C++ code is to make a working product, rather than to teach the world, using the elegant and expressive power of the C++ language is a great idea.

ChrisMM
  • 8,448
  • 13
  • 29
  • 48
Edward Brey
  • 40,302
  • 20
  • 199
  • 253
2

The only reason (that I can foresee) to not use value initialization for 'zeroing' is if you have special versions of memset/ZeroMemory(such as an SSE based one), or you need to avoid problems with the compiler(referring to MSVC here, as from VS2008 memset will never become an intrinsic, but with some clever coding(not using asm) you can force the intrinsic(REP STOS))

Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • @Anders: a friend of mine(Nefarius from d2mods.com) discovered this, if you create a simple fill loop: `while(pStart < pEnd) *pStart++ = dwFill;` then the compiler turns in into `REP STOS` this however doesn't work for memcpy. also the replacement code will also be vectorised(SSE2) or optimized better than a `msvcrt.memset` call, just note its up to you to handle alignment(I genereally use long's with a branch on `& 3` to catch left over bytes) – Necrolis Oct 05 '10 at 07:28
2

The only reason to prefer memset/ZeroMemory for this kind of initialization is if WinAPI functions require/expect the memory to be initialized that way, i.e. if WinAPI functions expect their zeros to be physical zeros - values with all-zero bit patterns.

Keep in mind that the difference between a representation of a zero value of some type and physical all-zero-bit pattern depends on the compiler implementation, not on OS. In theory, a Windows compiler can use non-zero bit patterns to represent zero values of various types. Like, a null pointer might be represented by non-zero physical value in some imaginary C or C++ compiler for Windows. (Not that anyone would actually do that, of course).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 3
    "In theory, a Windows compiler can use non-zero bit patterns to represent zero values of various types.". **No, it can not**. It wouldn't be a Windows compiler if it did. The reason is simple: the compiler can never know which zero value you'll `memcpy()` into an argument to a Win32 API. The Win32 API has one definition of a null pointer, all bits 0, and two definitions of a float (+0.0f/-0.0f). Hence, a Windows compiler must use this format everywhere. – MSalters Oct 04 '10 at 09:36
  • @MSalters: Incorrect. Windows compiler can use "non-zero" pointers. If WinAPI requires physical zero for "null pointers" in its interface, that would mean that with such a compiler the user would not be able to use language-level zero-initialization for WinAPI calls. The user would have to stick to `memset`/`ZeroMemory` approach for WinAPI-related initialization. It would be very inconvenient, error prone and would make no sense, which is why I said no one would ever do it. But there is noting impossible about it. – AnT stands with Russia Oct 04 '10 at 11:09
  • Your statement about "must use" is completely unfounded, even though it begins with "hence". – AnT stands with Russia Oct 04 '10 at 11:10
  • @AndreyT: How would it mean that you couldn't use language-level initialization? The Windows ABI *requires* the null pointer to be all-zero-bytes, so any compiler for windows will have to conform to that or it is not a Windows compiler. This is analogous to POSIX requiring `CHAR_BIT==8`. Any C compiler with `CHAR_BIT!=8` is not a POSIX compiler. – R.. GitHub STOP HELPING ICE Oct 04 '10 at 13:51
  • @R..: Windows ABI? Where did ABI come from? Who cares about ABI? One can easily implement a Windows compiler that gratuitously violates [almost] every requirement of Windows ABI, yet allows user to use WinAPI. In that case the user will be forced to perform all initializations for WinAPI "manually", at raw memory level (as in case of `memset`). As long as the user initializes everything properly and as long as the compiler follows the WInAPI calling convention everything will work properly. – AnT stands with Russia Oct 04 '10 at 14:44
  • It came from Microsoft. Your comments/answers lately have been bordering somewhere between feigned ignorance and trolling, so I'm giving up on explaining it anywhere beyond that. Ask a new question if you want to know what "Windows ABI" means. – R.. GitHub STOP HELPING ICE Oct 04 '10 at 15:00
  • @R..: Nothing in the above discussion so far had anything to do with Windows ABI. It was you who brought it up. Apparently, just to put some unnecessary noise into the discussion. My comments indicate only one thing: that I capable of grasping the difference between a standard language and a specific implementation (a very important thing to understand, BTW). It is not a surprise for me that anything related to that distinction draws random noise-based opposition from those who are not capable of grasping it. It's always been like that, not "lately". – AnT stands with Russia Oct 04 '10 at 15:29
  • @AndreyT : You wrote about "a Windows compiler". Either you mean a compiler that complies with the Windows APi and ABI, or you're trolling. – MSalters Oct 06 '10 at 07:30
  • @MSalters: The only parts of ABI a Windows compiler absolutely needs to support is the parts that are not under control of the user. That would be things like calling convention, i.e. everything that happens behind the scenes. As for the actual raw data passed to the API functions - in languages like C and C++ it is under virtually full user control. I.e. if the need arises, the user is capable of forming the proper values for passing to API function manually, at the very lowest level. – AnT stands with Russia Oct 06 '10 at 07:42
  • In this particular case, if the API expects/requires physically zeroed memory, the user can produce that zeroed memory by using `memset` (even if the language-level zero initialization like `= { 0 }` would not do that) and perform the proper call to the API function. That's the only point I'm trying to make. – AnT stands with Russia Oct 06 '10 at 07:43
2

The end result is identical (so long as you assume that 0 is always represented by all-zero-bits), so it's largely a matter of style. Personally, I prefer value initialisation, since it is simpler and doesn't require function calls.

Incidentally, you must initialise at least one member:

STRUCT theStruct = {0};

Omitting the 0 is allowed by some C compilers, but not by the C standard. C++ allows the omission, but I prefer to just always use the 0.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • 3
    C++ 8.5.1/8 says "An empty initializer-list can be used to initialize any aggregate". C requires at least one value. – dreamlax Oct 04 '10 at 07:55
  • Sorry, I was referring to C, but forgot to mention it. I've amended my answer. – Marcelo Cantos Oct 04 '10 at 08:11
  • 1
    A potentially important difference is that struct initialization doesn't need to initialize padding, so e.g. `memcmp()` might not return 0 for two structs whose values are otherwise identical (even before we get into -0.0). Assuming that writes to fields don't clobber adjacent padding (I don't know what C99 guarantees here), it's possible to violate an API contract that expects the struct to be zeroed with `memset()`, though it's a little farfetched. – tc. May 14 '13 at 15:08
  • 1
    In C++, `0` might not be a valid initializer for the first member, which is why `{ }` is preferred. – M.M Dec 08 '14 at 04:07
-2

in c++11:

struct A {
    int x = 10;
    int y = 100;
    int z = 0;
};

old style c++

struct A {
    int x;
    int y;
    int z;
    A() : x( 10 ), y( 100 ), z( 0 ) {} //constructor
};
vangodp
  • 9
  • 1