When MSDN says NULL, is it okay to use nullptr?


In various places, MSDN will talk about the behavior corresponding to the case where a handle type has the value NULL. A customer wanted to know whether it was safe to use nullptr in such cases, or whether they have to use NULL.

Although the programming languages used by MSDN for documenting Windows are putatively C and C++, MSDN understands that a lot of people write code for Windows in other languages, and therefore it tries to avoid relying on language subtleties.

Esoteric definitions for the term NULL is one of those language subtleties.

Formally, the C and C++ languages permit the following definitions for the NULL macro:

NULL 0 (void*)0 nullptr
C allowed allowed not allowed¹
C++ allowed not allowed² allowed

If NULL is defined as (void*)0 in C or as nullptr in C++, then it can be assigned only to a pointer type. And since MSDN cannot control how the C and C++ header files define NULL, it needs to work with any definition that is permitted by the corresopnding standards. Which means that saying NULL implies that the underlying type is a pointer type.

Therefore, you are welcome to write nullptr instead of NULL if you're writing C++ code. You're also welcome to write anything else that produces a null pointer, such as

HMUMBLE h1 = HMUMBLE();
HMUMBLE h2 = HMUMBLE{};
HMUMBLE h3 = HMUMBLE(0);
HMUMBLE h4 = (HMUMBLE)0;
HMUMBLE h5 = 3 - 3;

But most people would probably prefer you to write NULL or nullptr.

As noted, MSDN understands that a significant portion of its readership is not fluent in the subtleties of C and C++. When it writes NULL, it means the obvious thing: A null pointer. You can translate that into the appropriate construction for the language you are using. For example, for C#, you can use null, or if you are operating in raw IntPtrs, you can use IntPtr.Zero.

Bonus chatter: When MSDN says NULL, is it okay to use 0? Yes, but you probably don't want to. Using 0 as a null pointer constant is permitted by the C and C++ languages for backward compatbility reasons, but it's not considered modern style.

Bonus bonus chatter: I'm told that the Visual C++ folks occasionally entertain the possibility of changing the definition of NULL to nullptr, which is permitted by the standard. However, this ends up breaking a lot of code which assumed that NULL is an integral constant evaluating to zero. For example:

void foo(char* p)
{
  char c = NULL; // would not work if NULL were defined as nullptr
  *p = NULL;     // would not work if NULL were defined as nullptr
  ...
}

Although that code is technically already broken, it manages to work if NULL is defined as 0, and updating the definition in the language header files would break existing (albeit poorly-written) code.

¹ C does not have the nullptr keyword.

² C++ does not allow NULL to be defined as (void*)0 because C++ does not permit implicit conversion from void* to arbitrary T*.

int* p = (void*)0; // allowed in C but not C++
Comments (21)
  1. Medinoc says:

    I remember trying that someday, only to find there’s code in MFC headers (or/and windowsx, I don’t remember) that passes NULL to functions/methods expecting WPARAM or LPARAM.

  2. skeeto says:

    Technically “3 – 3” will not reliably produce a NULL pointer since the special rule for 0 only applies to the constant integer literal 0, not an expression that evaluates to zero.

    1. A null pointer constant is “an integer constant expression with the value 0″ (N1570 6.3.2.3p3).

      1. skeeto says:

        There was some confusion (issue #903) about how exactly to interpret that statement, concluding: “There was a strong consensus among the CWG that only the literal 0 should be considered a null pointer constant, not any arbitrary zero-valued constant expression as is currently specified.” The C++14 specification is much more specific: “A null pointer constant is an integer literal with value zero” (N4296 4.10p1). Neither Clang nor GCC will compile that line with “3 – 3” as C++11 or later.

        1. It looks like both gcc and clang implemented this change as a defect against C++11 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52145#c8

      2. Seth says:

        Current versions of the C++ standard say a null pointer constant is “an integer literal with the value 0 […]”, so expressions like ‘3 – 3’ don’t qualify in C++.

  3. Joshua says:

    I remember when HANDLE was an integer type and HANDLE h = 1; compiled.

    1. Anon says:

      “I remember when HANDLE was an integer type and HANDLE h = 1; compiled.”

      In Unix like OSs handles are traditionally integers. I wonder why Windows makes them a pointer? It seems like an index into a handle table and a pointer into that table are the same thing.

      1. Beldantazar says:

        Handles are usually not true pointers either, they’re an opaque vaue that has no meaning except for specific sentinel values.

      2. Joshua says:

        It permits the C compiler to yield warnings and the C++ compiler to yield errors on passing the wrong handle types to functions.

      3. Joshua says:

        So that the C compiler can issue warnings and the C++ compiler errors on passing the incorrect handle type to API calls.

      4. Dave Bacher says:

        Usually the integer approach is because of an array or table based implementation. I have a vector of some data structure, and I’m returning the index into that.
        In addition to what Joshua talks about with the compiler, using a pointer gives me the option of using some approach other than a table, array, or vector. That can help separate security concerns, and it can sometimes help performance or simplify code. I still have the option (since its an opaque value) of returning anything that floats my boat and fits into the variable, but if I can keep things separated off it is generally better than if I have things together in one spot.
        So as an example, if I have a process boundary, I can use malloc and I can put a security structure and book keeping structure at the pointer, followed by whatever data the handle is tracking, and I can return that pointer – and so then all my security code can be completely uniform, even if the data structures I’m tracking are non-uniform in size. If you think about it in C++ terms – I can have a base class with the security stuff, another base class with the handle tracking stuff, and then some class hierarchy for what I’m pointing at. With the traditional array approach, I’d allocate an array and then put a pointer to that in the array – and so I’m potentially saving a page operation, saving some memory on the CPU caches, etc. and so there could be a potential performance gain there when the system is under stress.

  4. Chris says:

    Regarding your insider info on changing NULL to be nullptr, there is this source (from 2013) corroborating that.

  5. Peter Doubleday says:

    Whatever happened to reading the documentation? (OK, we all know how that has worked out, over the years, but still.)

    If I’m programming in a version of C++ that has defined semantics for nullptr, I use nullptr … even if I happen to know that the current version of the current compiler silently treats nullptr as NULL or even as 0. And then I get to the API barrier …

    … which is where I convert (not cast: actually convert) the semantics of my chosen language to the semantics of the API. If the API guarantees correct behaviour with NULL, then so be it. Who am I to disagree? I don’t even care if NULL is defined in a BCPL-ish sort of way as -1.

    Anybody who bothers to ask this sort of question (“Do I really need to supply a NULL?”) has clearly never done much string manipulation in the old days. Pascal strings, BSTRs , Multi-char … shudder.

    Obey the Semantics, Luke.

    1. McBucket says:

      “Anybody who bothers to ask this sort of question (“Do I really need to supply a NULL?”) has clearly never done much string manipulation in the old days. Pascal strings, BSTRs , Multi-char … shudder.”

      Semantically, NULL is meant to represent a null pointer. Let’s not conflate/confuse this with the null-terminator used in C and C++, which, for ASCII strings is 0, which is named in ASCII as NUL. Yes, terminating a string with NULL will probably work, but:

      “Obey the Semantics, Luke.”

  6. Nico says:

    After using other languages, I find myself missing “nil” now as the non-value keyword when using C# or C++ (and nullptr is even more verbose than NULL!). And then there’s Obj-C where you can use use both…

    1. Azarien says:

      Talking of subtleties, sometimes I find myself writing `WNDCLASSEX wc = { sizeof(wc) };` when initializing structures with size as their first field.

      1. skSdnW says:

        This is wasteful on structs like OSVERSIONINFO where only the first field is input and the rest is output only. You might end up with a pointless call to memset in there when a simple MOV was all you really needed.

        1. Darran Rowe says:

          And then you have fun diagnosing problems when out only parameters or members of a structure randomly try to use any non zero values in that parameter or structure. There is a reason why initialising variables to a known value is so widely taught.

  7. I once answered a Stack Overflow question about the compatibility of nullptr and NULL when using C function https://stackoverflow.com/a/25656153/1708801

    I found it interesting that the C++ standard says that http://eel.is/c++draft/support.types.nullptr#2

    “The macro NULL is an implementation-defined null pointer constant”

    but only says this for cstdlib and it is an exception to it being the same as stdlib.h. The wording has changed a big between C++11 and the current draft but it would be nice if the standard spelled this out more clearly for other headers. There is some non-normative wording in Appendix C which extends what it says is a null pointer constant for more headers but none of them .h files.

    Basically, if you include a .h file from the C standard library the standard does not seem to give you are guarantee but the C++ versions of those headers it does.

  8. James says:

    “I’m told that the Visual C++ folks occasionally entertain the possibility of changing the definition of NULL to nullptr, which is permitted by the standard. However, this ends up breaking a lot of code which assumed that NULL is an integral constant evaluating to zero.”

    I think it would be nice if there were a way to opt-in to such a definition.

Comments are closed.

Skip to main content