You are not logged in.

#1 2019-04-08 18:12:54

Secreteus
Member
Registered: 2019-04-08
Posts: 4

[SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

Hi

I recently started learning C++ from C++ Primer by Stanley Lippman. In page 54 there is information that to use NULL I should include cstdlib. So I tried to find this definition. I run this command in /usr/include/c++/8.2.1:

cat $(find .) | grep NULL >> ~/out

and here is result:

      int __ret = pthread_rwlock_init(&_M_rwlock, NULL);
static void *thread_local_storage = NULL;
      if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
    return NULL;
    thread_id = NULL;
      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
          mutex->backend = NULL;
      mutex->backend = NULL;
      if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
          condition->backend = NULL;
      condition->backend = NULL;
  return __gthrw_(pthread_create) (__threadid, NULL, __func, __args);
    __gthrw_(pthread_mutex_init) (__mutex, NULL);
    __gthrw_(pthread_cond_init) (__cond, NULL);
static void *thread_local_storage = NULL;
      if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
    return NULL;
    thread_id = NULL;
      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
          mutex->backend = NULL;
      mutex->backend = NULL;
      if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
          condition->backend = NULL;
      condition->backend = NULL;
  return __gthrw_(pthread_create) (__threadid, NULL, __func, __args);
    __gthrw_(pthread_mutex_init) (__mutex, NULL);
    __gthrw_(pthread_cond_init) (__cond, NULL);
static void *thread_local_storage = NULL;
  return NULL;
static void *thread_local_storage = NULL;
      if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
    return NULL;
    thread_id = NULL;
      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
          mutex->backend = NULL;
      mutex->backend = NULL;
      if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
          condition->backend = NULL;
      condition->backend = NULL;
  return __gthrw_(pthread_create) (__threadid, NULL, __func, __args);
    __gthrw_(pthread_mutex_init) (__mutex, NULL);
    __gthrw_(pthread_cond_init) (__cond, NULL);
static void *thread_local_storage = NULL;
      if (__gthrw_(pthread_key_create) (&_objc_thread_storage, NULL) == 0)
    return NULL;
    thread_id = NULL;
      if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend, NULL))
          mutex->backend = NULL;
      mutex->backend = NULL;
      if (__gthrw_(pthread_cond_init) ((pthread_cond_t *) condition->backend, NULL))
          condition->backend = NULL;
      condition->backend = NULL;
  return __gthrw_(pthread_create) (__threadid, NULL, __func, __args);
    __gthrw_(pthread_mutex_init) (__mutex, NULL);
    __gthrw_(pthread_cond_init) (__cond, NULL);
static void *thread_local_storage = NULL;
  return NULL;
     *  Note that @p __seq may be NULL, in which case the iterator will be
     *  new container is the NULL pointer, the iterator is left
       * @pre @p seq is not NULL
       * @pre @p seq is not NULL
    /** The sequence this iterator references; may be NULL to indicate
        iterators. Only valid when _M_sequence != NULL. */
        iterators. Only valid when _M_sequence != NULL. */
     *  that @p __seq may be NULL, in which case the iterator will be
     *  new sequence is the NULL pointer, the iterator is left
  /** Non-NULL pointers are nonsingular. */
  /** Non-NULL pointers are dereferenceable. */
  /** Checks that __s is non-NULL or __n == 0, and then returns __s. */
  /** Checks that __s is non-NULL and then returns __s. */
       *  @param  __p  A pointer (defaults to NULL).
       *  @c NULL), then this has no effect.
       *  @param  __p  A pointer (defaults to NULL).
#undef __need_NULL
       *  If @p __sb is NULL, the stream will set failbit in its error state.
   *  @pre  @p __s must be a non-NULL pointer
   *  @brief Thrown when a NULL pointer in a @c typeid expression is used.
  /** @brief Token iterator for C-style NULL-terminated strings. */
  /** @brief Token iterator for C-style NULL-terminated wide strings. */
   *  accept NULL pointers.
       *  f.get(). If @a f is a NULL function pointer or NULL
       *  If @a f is a non-NULL function pointer or an object of type @c
       *  f.get(). If @a f is a NULL function pointer or NULL
       *  If @a f is a non-NULL function pointer or an object of type @c
       *  if @c typeid(Functor).equals(target_type()); otherwise, a NULL
   *  (the NULL pointer).
   *  (the NULL pointer).
       *  That's a lie.  We initialize the base class with NULL, because the
       *  That's a lie.  We initialize the base class with NULL, because the
       *  That's a lie.  We initialize the base class with NULL, because the
       *  That's a lie.  We initialize the base class with NULL, because the
       *  That's a lie.  We initialize the base class with NULL, because the
       *  That's a lie.  We initialize the base class with NULL, because the
          printf("NULL\n");
        // Points to next free thread id record. NULL if last record in list.
          // value for the byte order marker is NULL, so if this is
          // value for the byte order marker is NULL, so if this is
        // returns true. This would inevitably lead to a NULL pointer
#define PB_DS_ASSERT_AUX_NULL(X)                                        \
#undef PB_DS_ASSERT_AUX_NULL
  PB_DS_ASSERT_AUX_NULL((*this))
       *  If @p __sb is NULL, the stream will set failbit in its error state.
  /** @brief Token iterator for C-style NULL-terminated strings. */
  /** @brief Token iterator for C-style NULL-terminated wide strings. */
       *  __f.get(). If @a __f is a NULL function pointer or NULL
       *  If @a __f is a non-NULL function pointer or an object of type @c
       *  __f.get(). If @a __f is a NULL function pointer or NULL
       *  If @a __f is a non-NULL function pointer or an object of type @c
       *  if @c typeid(_Functor).equals(target_type()); otherwise, a NULL
   *  (the NULL pointer).
   *  (the NULL pointer).
       *  @return  A pointer to the tied stream, or NULL if the stream is
       *  @return  The previously tied output stream, or NULL if the stream
   *  @brief Determine whether the characters of a NULL-terminated
       *  @return  @c this on success, NULL on failure
       *  @return  @c this on success, NULL on failure
       *  @return  @c this on success, NULL on failure
       *  @return  @c this on success, NULL on failure
 *    @c NULL on error)
   *  expanded using realloc.  @a __output_buffer may instead be NULL;
   *  @param __length If @a __length is non-NULL, the length of the
   *  name, or NULL if the demangling fails.  The caller is

I don't see definition in output so my question is where it can be? Or maybe I used wrong commands and some files were skipped in search?

Last edited by Secreteus (2019-04-14 11:47:56)

Offline

#2 2019-04-08 18:56:36

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

That search command was a bit crazy, I think you meant

grep -r NULL /usr/include/c+\+/

or if you really want to use find

find /usr/include/c+\+/ -type f -exec grep NULL '{}' \+

But any of these are only looking in C++ headers, but the include is for the c standard library which is /usr/include/stdlib.h which includes stddef.h for the definition of NULL.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#3 2019-04-09 15:29:30

Secreteus
Member
Registered: 2019-04-08
Posts: 4

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

Trilby wrote:

That search command was a bit crazy, I think you meant

grep -r NULL /usr/include/c+\+/

This is exactly what I wanted.

Trilby wrote:

But any of these are only looking in C++ headers, but the include is for the c standard library which is /usr/include/stdlib.h which includes stddef.h for the definition of NULL.

I don't think I get it.
Command

cpp -v -x c++

results in

Using built-in specs.
COLLECT_GCC=cpp
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto
Thread model: posix
gcc version 8.2.1 20181127 (GCC) 
COLLECT_GCC_OPTIONS='-E' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/cc1plus -E -quiet -v -D_GNU_SOURCE - -mtune=generic -march=x86-64
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/x86_64-pc-linux-gnu
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/backward
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/include
 /usr/local/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/include-fixed
 /usr/include
End of search list.
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "<stdin>"
COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-E' '-v' '-mtune=generic' '-march=x86-64'

Let's say I want include header A which includes header B. My guess is it works like that:
1. Look for header A in /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1. If not found move to next directory in the list from above command.
2. Header A found. Now look for header B like for A header, starting from first directory from the list.

Due to that I don't understand why would preprocessor include file from directory you mentioned if cstdlib exists in /usr/include/c++/8.2.1.

Offline

#4 2019-04-09 16:50:21

V1del
Forum Moderator
Registered: 2012-10-16
Posts: 21,427

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

cstdlib does not define NULL. It does however include C's standard lib which is at the position pointed out by trilby.

// Need to ensure this finds the C library's <stdlib.h> not a libstdc++
// wrapper that might already be installed later in the include search path.
#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
#include_next <stdlib.h>
#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
#include <bits/std_abs.h>

Offline

#5 2019-04-09 17:34:30

Secreteus
Member
Registered: 2019-04-08
Posts: 4

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

V1del wrote:
#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS

What is the point of this line? How does exactly it affects include_next directive?

Offline

#6 2019-04-09 17:54:19

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

It affects any included file that checks whether that macro is defined, such the c++ version of stdlib.h

You could very easily determine this yourself with another simple grep command.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#7 2019-04-09 22:59:47

mpan
Member
Registered: 2012-08-01
Posts: 1,188
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

Secreteus:
Where and how it is actually defined is — from the perspective of a programmer — unimportant. All that is guaranteed is that if clocale, cstddef, cstdio, cstdlib, cstring, ctime or cwchar is included, the NULL macro is defined. It doesn’t even have to be in any actual file, a theoretically compiler is allowed to magically provide it¹.

C++ has nullptr instead of NULL. NULL is a macro that doesn’t produce a pointer — there is no technical way it could. It produces a number that is guaranteed to be converted to the null pointer while casted to a pointer type. When the cast is not occuring, you have a number — a trap for young players². On the other hand nullptr is a keyword that actually produces a null pointer³. Compare:

#include <iostream>
#include <cstdlib>

void foo(void* arg)
{
    ::std::cout << "foo(void* = " << arg << ")\n";
}

void foo(long arg)
{
    ::std::cout << "foo(long = " << arg << ")\n";
}

int main()
{
    foo(NULL); // In compiler’s eyes this is *literally*: foo(0L);
    foo(nullptr);
    return EXIT_SUCCESS;
}

Now the part less about “should” and more about “is”.

The way the standard library provides NULL, and actually any feature defined in the legacy C library, is a bit convoluted. Theoretically C++ standard library should be independent of the C standard library and is not compatible with that of C. C++ defines both “c*” and “*.h” versions of the headers (for example “cstdio” and “stdio.h”), the “c*” version should define everything and the “*.h” version should include that header and contain a bunch of `using ::std::feature_name` to import everything into the global namespace. This is the theory. In practice it depends on the imlementation. For various reasons many standard libraries do not define C++ version of “*.h”. Instead, they use C headers⁴ — perhaps even system headers. The “c*” versions of headers include those and create a somewhat complex patchwork in the std namespace to obtain what C++ requires.

The bottom line is: where NULL is defined depends heavily on the particular implementation, sometimes even the version of the standard library. It may be defined in C++ library itself, it may be in C library, it may be among some platform-specific headers.
____
¹ Not done in practice, AFAIK.
² In C the distinction wasn’t that important in most cases, because C had no function overloading and templates. However, C had its trap too: a NULL in variadic functions. It may also be amibiguous in _Generic.
³ Technically: it produces a value of type ::std::nullptr_t, that is equal to the null value of any pointer type.
⁴ One of the reasons you should never use the “*.h” versions of standard headers in C++, despite theoretically C++ guarantees they are containing C++ definitions. Unless you really want to include the C headers — for example for system APIs.


Sometimes I seem a bit harsh — don’t get offended too easily!

Offline

#8 2019-04-10 00:25:41

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

mpan wrote:

NULL is a macro that doesn’t produce a pointer — there is no technical way it could...

   foo(NULL); // In compiler’s eyes this is *literally*: foo(0L);

Can you elaborate on this?  How is the following not a macro that produces a pointer, and how would it not invoke the second version of 'foo':

#define NULL   ((void *) 0)

This is in fact the definition that is generally quoted.  In which case this would expand, in your example to the following:

foo(((void *) 0));

This would call the pointer version of foo and not be the same as `foo(0L);`.

Last edited by Trilby (2019-04-10 00:25:59)


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#9 2019-04-10 06:57:02

mpan
Member
Registered: 2012-08-01
Posts: 1,188
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

Trilby:
The definition you have provided is one of the possible definitions in C. In C++ it is always an integer literal equal to 0 — it can’t be defined in any other way, because C++ has no implicit conversion from void*. This is why nullptr has been added — unlike C, C++ has no universal pointer type.

Normative/quasi-normative references:
In C11:
“The macros are NULL which expands to an implementation-defined null pointer constant” (7.19§3)
“An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant” (6.3.2.3§3)
The wording is the same in C99 (7.17 and 6.3.2.3, respectively).

IEEE 1003.1:2017:
“A pointer obtained by converting an integer constant expression with the value 0, or such an expression cast to type void *, to a pointer type” (3.249). Note that POSIX assumes C as the underlying language.

In C++03:
“The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10). [180]” (18.1§4)
With footnote [180]: “Possible definitions include 0 and 0L, but not (void*)0.”
“A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero” (4.10§1)
The wording is the same in C++98.

In C++17 working draft (N4659 version):
“The macro NULL is an implementation-defined null pointer constant. [186]” (21.2.3§2)
With footnote [186]: “Possible definitions include 0 and 0L, but not (void*)0.”
“A null pointer constant is an integer literal (5.13.2) with value zero or a prvalue of type std::nullptr_t.” (7.11§1)
The current draft seems to permit a value of type ::std::nullptr_t instead of only integer 0.

Historically, the 0 as NULL is the oldest, found in various K&R publications, both in examples for the earliest manuals, and in the classic “The C programming language”, before C had NULL defined as a part of its standard library: “it is guaranteed that assignment of the constant 0 to a pointer will produce a null pointer” (7.14), which is later exploited with an explicit definition in 5.4. Later, in second edition, it has been part of the already existing stdio.h and described as: “The symbolic constant NULL is often used in place of zero, as a mnemonic to indicate more clearly that this is a special value for a pointer”. This edition is also prohibiting using of other integers, unlike the original K&R.

In GNU/libc (C):
“Macro: void * NULL
This is a null pointer constant.
You can also use 0 or (void *)0 as a null pointer constant” source

In GNU/libstdc++ (C++):
“The only change that might affect people is the type of NULL: while it is required to be a macro, the definition of that macro is not allowed to be (void*)0, which is often used in C.” source

Non-normative references:
C: “Therefore, the preprocessor macro NULL is defined (by several headers, including <stdio.h> and <stddef.h>) as a null pointer constant, typically 0 or ((void *)0)” (5.4 of C-FAQ).

C++ :
Indirectly implied by: “A problem with both NULL and 0 as a null pointer value is that 0 is a special “maybe an integer value and maybe a pointer” value. Use 0 only for integers, and that confusion disappears.” (C++ FAQ)

Experimental evidence:
Just check the code I’ve provided. It shows which type the compiler uses.

For inability to have NULL as (void*)0 in C++:

void foo()
{
    int* x = (void*)0;
}

For checking that NULL is indeed defined as 0 or something that can be converted to int¹:

#include <cstdlib>

void foo()
{
    int y = NULL;     // No error, because `NULL` evaluates to `0` 
    int x = (void*)0; // Error
}

____
¹ Modern compilers, which already support ::std::nullptr_t, will make use of that feature while compiling C++ code.

</xkcd-386>

Last edited by mpan (2019-04-10 07:17:56)


Sometimes I seem a bit harsh — don’t get offended too easily!

Offline

#10 2019-04-10 12:27:33

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

I do get a compiler error on the line you say would not give one:

$ cat test.cpp
#include <cstdlib>

int main()
{
    int y = NULL;     // No error, because `NULL` evaluates to `0`
    int x = (void*) 0; // Error
         return 0;
}


$ g++ -o test test.cpp
test.cpp: In function ‘int main()’:
test.cpp:5:13: warning: converting to non-pointer type ‘int’ from NULL [-Wconversion-null]
     int y = NULL;     // No error, because `NULL` evaluates to `0`
             ^~~~
test.cpp:6:21: error: invalid conversion from ‘void*’ to ‘int’ [-fpermissive]
     int x = (void*) 0; // Error

There is no error from "(void *) 0", but there is one from trying to cast that to int.  I didn't know that NULL was defined differently in C++ than in C, but I still don't understand how you claim a macro couldn't be a (void *) 0 pointer.

$ cat test.cpp

#include <iostream>
#include <cstdlib>

void a(int arg) {
        ::std::cout << "running 'a' on an int\n";
}

void a(long arg) {
        ::std::cout << "running 'a' on a long\n";
}

void a(void *arg) {
        ::std::cout << "running 'a' on a pointer\n";
}


int main() {
        a(((void *) 0));
        a(MY_NULL);
        return 0;
}

$ g++ -o test test.cpp

$ ./test
running 'a' on a pointer
running 'a' on a pointer

Further testing confirms that NULL is indeed not a pointer in C++, but I don't understand the claim that a macro/constant could not possibly be defined as a pointer - the example above shows that a C-style null pointer will indeed call the right version of the 'a' function, and further shows that a macro/constant defined as such a null pointer (MY_NULL) will indeed work as intended.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#11 2019-04-10 23:21:32

mpan
Member
Registered: 2012-08-01
Posts: 1,188
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

Trilby wrote:

I do get a compiler error on the line you say would not give one:

This is a warning, not an error¹. The compiler is noticing that the code does something, that is valid from the language’s point of view, but from practical point of view is probably a mistake.

Trilby wrote:

(…) I still don't understand how you claim a macro couldn't be a (void *) 0 pointer.

It couldn’t be, because the language specification says it can’t be. It also can’t be, becaue it must cause an error, which it causes — as seen in the provided example.

Trilby wrote:

(…) the example above shows that a C-style null pointer will indeed call the right version of the 'a' function, and further shows that a macro/constant defined as such a null pointer (MY_NULL) will indeed work as intended.

Yes, because you have defined it as a (void*)0 — or I guess you did. The best matching function overload for an argument of type void* is the one which has parameter of type void*, and therefore it is called. Both lines are identical², so they cause identical behaviour. After preprocessing:

// … Over 20000 lines from headers

void a(int arg) {
        ::std::cout << "running 'a' on an int\n";
}

void a(long arg) {
        ::std::cout << "running 'a' on a long\n";
}

void a(void *arg) {
        ::std::cout << "running 'a' on a pointer\n";
}


int main() {
        a(((void *) 0));
        a(((void *) 0));
        return 0;
}

___
¹ Normally I would argue that any warning in -Wall is an error too, but this discussion is about the language itself and not about coding practices/mistakes. Without additional options g++ returns errors only for language errors. Warnings are g++’s own observations on what could potentially be wrong from practical point of view.
² Under assumption that MY_NULL is defined a (void*)0.

Last edited by mpan (2019-04-10 23:23:24)


Sometimes I seem a bit harsh — don’t get offended too easily!

Offline

#12 2019-04-10 23:42:26

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,449
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

Yes, sorry, it was a warning.  But the text of it: "converting to non-pointer type ‘int’ from NULL" .  Why is converting NULL to a non-pointer type worth a warning if NULL is not itself a pointer type?

As for your claim that a macro could not be a "(void *) 0" pointer, you still say it couldn't be and that it must cause an error.  But I just showed code where there was a macro of that type and it did not cause an error.  It clearly is possible.

A further demonstration:

$ cat test.cpp

#include <iostream>
#include <cstdlib>
#include <typeinfo>

#define MY_NULL   ((void *) 0)

int main() {
        ::std::cout << typeid(NULL).name() << "\n";
        ::std::cout << typeid(MY_NULL).name() << "\n";
        return 0;
}

$ g++ -o test test.cpp

$ ./test
l
Pv

Last edited by Trilby (2019-04-10 23:46:11)


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#13 2019-04-11 03:11:33

mpan
Member
Registered: 2012-08-01
Posts: 1,188
Website

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

Trilby wrote:

Why is converting NULL to a non-pointer type worth a warning if NULL is not itself a pointer type?

Because NULL is used in the code to indicate a pointer (no matter if it actually replaced by a pointer-type or not). So assigning NULL to an integer makes as much sense as this:

int x = "bleh"; // Invalid in both C and C++¹; used only to show an assignment that makes no sense

It is possible to convert a pointer to a suitably big integer², but that requires an explicit cast:

static char const bleh[] = "bleh";

// In C++:
::std::uintptr_t ptr = reinterpret_cast<::std::uintptr_t>(bleh);
char const* str = reinterpret_cast<char const*>(ptr);

// In C:
uintptr_t ptr = (uintptr_t)bleh;
char const* str = (char const*)ptr;

Note that we’re losing any CV information if we are converting to an integer. But there are some very rare, platform-dependent cases in which that may be needed. But the explicit cast is required. Otherwise it would be too easy to make a simple mistake like that:

int* x = whatever;
int xPtr = &x;
int y = xPtr; // oops! I meant y = *xPtr

As for your claim that a macro could not be a "(void *) 0" pointer, you still say it couldn't be and that it must cause an error.  But I just showed code where there was a macro of that type and it did not cause an error.

But your code uses it in a completely different situation. Sure, there are contexts in which having (void*)0 in C++ would not cause errors. A much simpler one:

void foo()
{
    (void*)0;
}

But that doesn’t invalidate the fact, that you can’t use (void*)0 in nearly all contexts in which NULL is used. And I have shown an example of such a very typical situation.
____
¹ Historically it has been a valid code, though. In relaxed mode GCC still permits it.
² In C: uintptr_t, intptr_t from “stdint.h” (also “inttypes.h”). In C++: ::std::uintptr_t, ::std::intptr_t from “cstdint”.

Last edited by mpan (2019-04-11 03:14:11)


Sometimes I seem a bit harsh — don’t get offended too easily!

Offline

#14 2019-04-14 11:33:34

Secreteus
Member
Registered: 2019-04-08
Posts: 4

Re: [SOLVED] C++ - NULL definition location, g++ 8.2.1 compiler

Thanks for help, it was enlightening read.

Offline

Board footer

Powered by FluxBB