views:

161

answers:

4

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?

+2  A: 

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
Could you share this MSVC trick?
Anders
Necrolis
+2  A: 

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).

AndreyT
"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
@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.
AndreyT
Your statement about "must use" is completely unfounded, even though it begins with "hence".
AndreyT
@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..
@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.
AndreyT
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..
@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".
AndreyT
@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
@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.
AndreyT
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.
AndreyT
+1  A: 

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
C++ 8.5.1/8 says "An empty initializer-list can be used to initialize any aggregate". C requires at least one value.
dreamlax
Sorry, I was referring to C, but forgot to mention it. I've amended my answer.
Marcelo Cantos
+4  A: 

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.

jdv
It's worth noting that OP tagged the question both C and C++, but `STRUCT theStruct = {};` is **not valid C**. You need `{0}` instead.
R..
@R.: I'll edit.
jdv