6

When studying the sample code for this question I had assumed it was Undefined Behaviour which was preventing subsequent uses of std::cout from printing. But it turns out that attempting to print a null pointer caused std::ios_base::badbit and std::ios_base::failbit to be set in its stream state which was the real cause for its being non-operational. Because of this, I am now curious if it really is Undefined Behaviour to (attempt) to print a null-pointer. So here are my questions:

  1. Is it Undefined Behaviour to print a null-pointer? If so, what is it about the stream inserter that would cause this? I'm pretty certain the inserter is smart enough to not dereference a null-pointer.

  2. I would also like to know why the inserter sets its error mask when encountering a null-pointer in this context (specifically badbit). Why doesn't it treat it like the termination of a string literal?

I don't have a Standard handy, and I only found one source thus far that unfortunately led to a dead link.

Community
  • 1
  • 1
David G
  • 94,763
  • 41
  • 167
  • 253
  • 1
    libstdc++ might be doing an extra `nullptr` check when it's not required to. The program [seg faults](http://coliru.stacked-crooked.com/a/2078b21d2ce9050d) when you build it with clang+libc++. but not with clang+libstdc++ – Praetorian Apr 25 '14 at 04:00
  • 2
    "I'm pretty certain the inserter is smart enough to not dereference a null-pointer." - generally, the C++ standard says what compilers must do, and anything else, they don't have to do. It would slow down correctly-coded programs to do an extra NULL check before every call to `operator<<(char *)`. – M.M Apr 25 '14 at 04:10
  • @MattMcNabb: lol I don't think the speed of a null check is a concern when working with something as horribly slow as C++ I/O streams. – user541686 Apr 25 '14 at 04:56
  • **Closely related:** http://stackoverflow.com/q/7019454/560648 (almost a dupe, tbh) – Lightness Races in Orbit Dec 05 '14 at 15:38

2 Answers2

12

basic_ostream's operator<<(basic_ostream<>&, const char*) function requires that the char* is non-null - it is designed to print the string the pointer points to. So it is undefined behavior to send a null char* to cout. (See C++11 27.7.3.6.4/3 "Character inserter function templates").

However, basic_ostream's operator<<(basic_ostream<>&, const void*) function simply prints the value of the pointer, so a null pointer will work properly with that overload.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 6
    If you quote the standard via `[ostream.inserters.character]` instead of doing `27.7.3.6.4` then it has more chance of still being a valid reference in a different version that may have renumbered chapters or sections. – M.M Apr 25 '14 at 04:11
2

gcc ostream.tcc line 319:

template<typename _CharT, typename _Traits>
  basic_ostream<_CharT, _Traits>&
  operator<<(basic_ostream<_CharT, _Traits>& __out, const char* __s)
  {
    if (!__s)
__out.setstate(ios_base::badbit);

gcc is simply performing a check that the standard does not guarantee, which is fine because it's undefined anyway.

user657267
  • 20,568
  • 5
  • 58
  • 77