Why do Microsoft code samples tend to use ZeroMemory instead of { 0 }?


If you go browsing around MSDN, you'll find that code samples tend to call ZeroMemory explicitly rather than using "= { 0 }" notation. Why is that?

To make it clearer for people who are used to other programming languages.

Like it or not, a significant percentage of people who write programs for Windows do it in languages other than C and C++. Although those developers may have a basic understanding of C and C++, they don't have all the language subtleties memorized.

Compare the situation of speaking in English to a group of people where not everyone speaks the language fluently. If you're considerate of your audience, you're going to avoid the more esoteric grammatical constructions, the rare words, and the obscure idioms. Instead of saying, "Were it to rain, we will see that umbrellas be available," you would use the simpler "If it rains, then we will make sure that umbrellas are available," thereby avoiding the grammatical complexity of the implied conditional by inversion ("if"), the subjunctive of condition ("were"), the implied conclusion ("then"), and the subjunction of intention ("be").

Heck, even people who claim to know C and C++ don't have all the language subtleties memorized. Some of them have false impressions of what " = { 0 }" does. And who among us really has C/C++'s bizarre operator precedence rules committed to memory?

Consequently, MSDN samples tend to use ZeroMemory to make it blindingly obvious what is being set to zero. One of the things we've learned over the years is that many people just copy/paste sample code without understanding it. If there are little things like ZeroMemory that can be done to make the intent of sample code clearer and reduce translation errors, then that's a good thing.

If you prefer " = { 0 }", then go ahead and use it, secure in the knowledge that thousands of programmers aren't going to read your code and try to translate it into Visual Basic because that's the only language they know. But MSDN doesn't have that luxury.

Comments (24)
  1. asdf says:

    I prefer to use = { }; but unfortunately that only works in C++ and not C. ZeroMemory isn’t the same thing as using { 0 } though. The later may or may not set padding bits to zero and of course the standards make no guarantee about an object representation of all bits zero being mapped to a value of zero (except until recently when a defect report made that constraint true for integers). In practice, all platforms that programmers actually enjoy programming for, they mean the same thing.

  2. E. Massey says:

    I’ve found that using ZeroMemory (or ZERO_INIT, a similar macro) is frequently a better choice for me since it can accomodate changes to the data structure definition (e.g. adding a new field on the end).

    For C++, though, if the structure has a constructor, either explicit or implicit, then you’ve got to be careful not to blow over any non-NULL initialized pointers (e.g. sentinels) if you zero-init after constructing the object. In this case, assigning it to a global const object will do the trick (without the padding, however).

    For debugging, zero-init clears any structure padding to help prevent mistaking uninitialized data for real values when debugging with hex dumps.

  3. Ulric says:

    It’s not really true that ZeroMemory could generate different code. The context in which it is used in these samples is to zero the memory of structures on the stack, not static variables. It’s just a define to memset.

    The post above is not advocating using ZeroMemory instead of constructors for C++ objects, just that it’s used to zero C structures and arrays to null bytes. And yes, float 0.0 is an IEEE standard.

    It’s called ZeroMemory : It does exactly what it says : sets memory bytes to value zero, and no more. In Windows if a structure has a pointer that needs to be NULL if not used, it needs to be of the bit pattern zero, it is not a compiler decision, it’s not language-specific, but something that you pass to the OS. ZeroMemory is the clearest way to zero these structures.

  4. CornedBee says:

    Why does anyone care about hypothetical cases containing padding bits and non-IEEE floating point numbers? We’re talking about Windows here. It runs on x86, IA64, x86-64, an unsupported old version on Alpha, and various embedded devices. All of them use 2’s complement signed representations, no padding bits and IEEE floats, if they support floats at all. (Not sure if that’s a hardware requirement for WinCE.) Bitfields never appear in any place of the WinAPI. (They wouldn’t be properly portable to other languages.)

    For all intents and purposes, {0} and ZeroMemory are 100% identical in Windows programming.

  5. Kevin says:

    CornedBee: Bitfields never appear in any place of the WinAPI.

    Take a look at the definition of the DCB strucutre.

  6. Hypertarded CPU says:

    Some day people will learn not to state absolutes in this blog :)

  7. Karan Mehra says:

    Let’s not forget unions

    If the structure being initialized is a union or includes a union, then only the first field of the union will be zeroed. If this field isn’t the largest one in the union, then you end up with uninitialized data!

  8. ryanmy says:

    "All of them use 2’s complement signed representations"

    That’s not just Windows. The C++ language spec (ISO/IEC/INCITS 14882:1998) requires that any target machine must use 2s complement for signed ints and straight unsigned numbers for unsigned ints. Period. So it’s safe from that perspective as well :) C, I’m not so sure on, but I think (correct me if I’m wrong) that it offers the same guarantee.

    As for NULL, I can only think of one C platform that ever used a pattern other than all zeros for NULL — and that was Honeywell-Bull. In C++, at least, you are guaranteed that casting the integer 0 to any pointer type results in an appropriate null pointer value for that platform. (Granted, this is NOT what ZeroMemory is guaranteed to do. But it results in the same thing on every platform that Windows currently runs on.)

    The only time it’s not safe are in floats, because C/C++ put no standards on it. I think, though, that every platform Windows currently runs on uses IEEE754.

  9. Adrian says:

    I like the explanation of being explicit and avoiding the less well-known "features" of a language. It’s something I strive for in the code I write.

    On the other hand, ZeroMemory doesn’t do exactly what ={0} does. Although it’s unlikely, the difference could lead to portability problems.

    Consider a struct with pointers and floats. The ={0} initialization will set the pointers to null and the floats to 0.0. But ZeroMemory will just set all the *bits* of those fields to 0. If null pointers are represented by all-zeroes (which is true for most but not all platforms), then you’re fine. I’m less familiar with the representations for floating point numbers. Is 0.0 always represented with all-zeroes?

    One other difference is bit-fields. Sayeth K&R: "Unnamed bit-field members are ignored, and are not initialized." Zero memory is going to clear all of the bitfields in your struct, but the ={0} technique does not.

    And lastly (because it really shouldn’t be an important consideration until your performance profile says it is), these two techniques may optimize differently. ZeroMemory is a function call (possibly inlined?) that will set the memory block to 0. An initialized structure, however, may just copy bits from the executable into the desired memory slot.

    On VAX/VMS, there was a special optimization for statics that were to be initialized to all-zeroes. Rather than storing an appropriately-sized block of zeros in the executable, the variables were mapped to "demand zero-page", which relied on a feature of the memory manager to provide pages of all-zeroes when those addresses are first paged into RAM. This same feature was responsible for calloc being significantly faster than malloc + memset to zero.

  10. Dean Harding says:

    I think the point is that while ‘= {0}’ is not always the same as ZeroMemory that when they differ, it’s the ZeroMemory behaviour that you (as in, the person using the Windows API) wants. Otherwise it wouldn’t be called ZeroMemory.

    Just another reason to always be explicit and only make micro-optimizations like ‘= {0}’ when it’s actually required.

  11. Ulric: as Adrian points out, a NULL pointer is not necessarily a "the bit pattern zero".

    void* p = NULL;

    is not the same as

    void* p;

    ZeroMemory(&p, …);

  12. asdf says:

    ryanmy: C++[3.9.1/7] "[Example: this International Standard permits 2’s complement, 1’s complement and signed magnitude representations for integral types.]". Ditto for C.

  13. Norman Diamond says:

    Tuesday, June 28, 2005 5:41 PM by ryanmy

    > The C++ language spec (ISO/IEC/INCITS

    > 14882:1998) requires that any target machine

    > must use 2s complement for signed ints and

    > straight unsigned numbers for unsigned ints.

    > […] C, I’m not so sure on, but I think

    > (correct me if I’m wrong) that it offers the

    > same guarantee.

    C sure doesn’t. Last I saw, the C standard still has a defect where, in a one’s complement environment and a program that uses both signed chars and unsigned chars and reads one byte from a file, the standard essentially guarantees that the implementation is going to read the programmer’s mind in order to know how to convert the value. That didn’t persuade the committee to remove the possibility of an implementation being one’s-complement.

    By the way in K&R C there was no such problem. One’s-complement implementations could conform very easily in those days.

    > As for NULL, I can only think of one C

    > platform that ever used a pattern other than

    > all zeros for NULL

    Yeah, that’s really too bad. It would have been possible for implementations on Intel systems to use all one-bits (0xFFFF:0xFFFF or 0xFFFF:0xFFFFFFFF etc.) and get hardware assistance in catching some buggy programs that dereferenced null pointers. But no, no one wants to get their bugs caught and fixed.

  14. Brooks Moses says:

    I think I’m going to have to make a grammar-pedant comment here (given that I’m not enough of a C++ programmer to know what you’re talking about in the rest of the entry!). The first of your example sentences doesn’t use the subjunctive tense properly; it should instead be: "Were it to rain, we would see that umbrellas would be available."

    The use of the subjunctive in this case also creates an impression that the speaker is certain that it’s not going to rain. Thus, if your example were to be used to reassure people who expected it to rain, you would also want to use the "if it rains, then we will…" construction for that reason.

  15. Simon Cooke says:

    Norman Diamond wrote:

    ———————————-

    Yeah, that’s really too bad. It would have been possible for implementations on Intel systems to use all one-bits (0xFFFF:0xFFFF or 0xFFFF:0xFFFFFFFF etc.) and get hardware assistance in catching some buggy programs that dereferenced null pointers. But no, no one wants to get their bugs caught and fixed.

    ———————————-

    Erm… it already does have hardware assistance. There’s a guard page there. It’s also why you get EXCEPTION_INVALID_ACCESS_VIOLATION when you dereference a NULL pointer.

  16. "If you prefer " = { 0 }", then go ahead and use it, secure in the knowledge that thousands of programmers aren’t going to read your code and try to translate it into Visual Basic because that’s the only language they know. But MSDN doesn’t have that luxury."

    I thought this was moot, since VB will initialize structs to zero for you. If the VB programmer decides to manually assign zero to every value, it won’t keep the program from working, it will just be redundant code. Those same programmers might copy the call to ZeroMemory even when it wasn’t needed.

    Anyway, this is splitting hairs. I agree about mindless copying of code. Look at all the VB Declare statements being ported to .NET with ABSOLUTELY no regard for 64-bit machines. VB6 didn’t have a 64-bit version, but .NET does, so the decision to use Int32 or IntPtr is very important, and over half of the code on the Internet seems to get it wrong.

    I worry about moving to 64-bit with too many careless programmers around. I assume the problem is similar in the unmanaged world, but at least you have to recompile the application to even attempt to run it in 64-bit.

  17. Bristol Technology and Mainsoft have software (Wind/U and MainWin) to build Windows applications on other OSes.

    There is a difference between the Win32 API and the Windows OS.

  18. Ulric says:

    Right.. as one person replied above, discussion of the bit pattern of NULL is not important. The goal of ZeroMemory is to zero a struct you pass it to the Win32 API, not produce a NULL pointer bit pattern for your compiler. :^)

  19. Ulric says:

    Btw, Bristol( hasn’t that gone out of business?) and MainSoft do not allow to make Win32 software on just any configuration and theorical compiler. The compiler must meet some specific requirements, like having a v-table layout that is compatible with COM. MainSoft has a modified version of GCC and each version requires one compiler. On thing that can happen is that you can use MainWin on a machine that is big-endian instead of little endian, but that’s as far as you’ll be away from the bitwize representation from your WinTel machine.

  20. ts says:

    Allan Bauer, at http://blogs.borland.com/abauer/archive/2005/06/29/20035.aspx, says that "asdf" here is a "glory seeker" for pointing out some factual details about { 0 } vs. ZeroMemory. "glory seeker"? For simply pointing out some facts? I’d say that Allan Bauer is an anti-intellectual jackass *and* a glory seeker.

  21. Mark Anderson says:

    CornedBee said:

    "Why does anyone care about hypothetical cases containing padding bits and non-IEEE floating point numbers? We’re talking about Windows here. It runs on x86, IA64, x86-64, an unsupported old version on Alpha, and various embedded devices."

    Bits of windows systems get ported to the strangest places; I was involved in a port of the Windows Media system to a custom VLIW processor with it’s own compiler, and every Windows centric assumption cost us bigtime. We knew we were going to rewrite the inner loops for our architecture, but we didn’t realize how much pain the support infrastructure would be. There was ASF, and DRM, and and …

    New platforms keep on showing up; the XBox2 PowerPC derivative isn’t on your list. Yes, it is a 2’s complement, IEEE machine, but it might not have been. Why take the gamble when doing the right thing is often a moment’s work?

  22. TC says:

    "secure in the knowledge that thousands of programmers aren’t going to read your code and try to translate it into Visual Basic because that’s the only language they know"

    Huh? Haven’t all those people automagically converted their millions of lines of VB[A] code, into .NET?

    TC :-(

  23. James says:

    For all those people wondering whether there’s actually a case when ZeroMemory differs from C++’s idea of zero initialization, I think Raymond did a few peices on pointers to members. He could have mentioned it then. Bitfields have already been mentioned, and I think only the first member of a union is zeroed (of course, it will overlap with others). There’s basically no guarantee of gaps between objects having a value.

    I wonder who thought ZeroMemory was so much more readable than memset, though.

  24. To somebody who doesn’t know C well, it’s not obvious whether

    memset(&s, 5, 10);

    sets five bytes to 10 or ten bytes to 5. Heck even I don’t know.

Comments are closed.