3

Since C++11, the Standard allows the macro NULL to either be a integer literal with value zero, or a prvalue of type std::nullptr_t.

Any Standard Library vendor deciding to change their definition of NULL from an integer to nullptr would very likely cause breakage for clients relying on pre-C++11 code.

Does any major implementation (e.g. GCC, Clang, MSVC) actually define NULL as nullptr? Or, despite the possibility, does nobody do this?

20
  • 3
    You can trivially determine this for your toolchain (indeed, for all three). Are you experiencing some practical problem with obtaining this information? Commented May 9, 2020 at 16:11
  • 5
    If changing NULL from 0L to nullptr breaks your code, your code has always been broken imho. Commented May 9, 2020 at 16:17
  • 1
    @AsteroidsWithWings what do you mean by "Shared with C"? It's usually 0L for C++ and (void*)0 for C with #ifndef __cplusplus. Commented May 9, 2020 at 16:19
  • 1
    @Ayxan Ah, really? Did not know that. Commented May 9, 2020 at 16:20
  • 3
    For reference, STL had an anecdote about trying to change this and running into a bunch of problems within their own code: youtu.be/AKtHxKJRwp4?t=3437. OTOH, there was this tweet some years later, same person.
    – chris
    Commented May 9, 2020 at 16:40

1 Answer 1

4

libstdc++ relies on including stddef.h, which defines NULL in the following way:

// <stddef.h>
//
#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL     /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else   /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else   /* C++ */
#define NULL 0
#endif  /* C++ */
#endif  /* G++ */
#endif  /* NULL not defined and <stddef.h> or need NULL.  */
#undef  __need_NULL

Information about __null can be found in this question:

The implementation of __null is as a G++ internal. Basically, the internal does what you would naively expect reinterpret_cast<void *>(0) to do.

Its type is 'magic', depending on context. That's the reason G++ had to implement it as an internal. No regular type provides the precisely-correct semantics. It acts roughly like void *, but not exactly.


libc++ does pretty much the same thing:

// <cstddef>
//
// Don't include our own <stddef.h>; we don't want to declare ::nullptr_t.
#include_next <stddef.h>
#include <__nullptr>

Microsoft's STL also relies on including stddef.h:

#pragma once
#ifndef _CSTDDEF_
#define _CSTDDEF_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR

#include <stddef.h>

I could not find stddef.h in the open-source STL repository, but a definition of NULL is provided in vcruntime.h:

#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else
        #define NULL ((void *)0)
    #endif
#endif

A simple test on icc 19.0.1 also shows that NULL is not defined as nullptr:

#include <type_traits>
#include <cstddef>

static_assert(!std::is_same<decltype(NULL), std::nullptr_t>::value, "");
static_assert(!std::is_same<decltype(NULL), int>::value, "");
static_assert(std::is_same<decltype(NULL), long>::value, "");

live on godbolt.org

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.