3

Possible Duplicate:
Why does std::cout output disappear completely after NULL is sent to it

It seems if you try:

 std::cout << NULL << endl;
 std::cout << "hell" << endl;

it print out nothing and C++ IO stops working for all subsequent outputs.

but it works fine in C stdio:

 printf("%s\n", NULL);
 printf("%s\n", "hell"); 

(null)

hell

Is there any good reason why C++ IO can't do the same thing?

(edited in response to comments) alright, to make it clear, NULL does have a type, say const char*

const char* getxxx();  // may return NULL, 
cout << getxxx();      // won't work if NULL returned
Community
  • 1
  • 1
  • 1
    what compiler are you using? – Andy Prowl Jan 25 '13 at 17:14
  • 6
    I'm not sure that the standard defines how `printf` handles a null pointer for `%s`. – Oliver Charlesworth Jan 25 '13 at 17:15
  • 2
    Is this the ACTUAL code you are referrring to, or are you actually doing something else. And I agree with Oli - printf isn't defined to handle NULL - in fact it may well NOT handle it. – Mats Petersson Jan 25 '13 at 17:16
  • `std::cout << NULL << endl;` [works just fine](http://ideone.com/QkGMNp). I think you mean something more like [`std::cout << (char*)NULL << endl;`](http://ideone.com/IeBdeJ). – Cornstalks Jan 25 '13 at 17:27
  • @OliCharlesworth It doesn't; it's undefined behavior. But he's not talking about a null pointer; his examples pass a null pointer constant, which isn't a pointer (and on my machine, doesn't even have the same size as a pointer). – James Kanze Jan 25 '13 at 17:45

2 Answers2

14

Huh? I see no reason why cout should fail simply because you executed

std::cout << 0 << std::endl;

It should output 0\n. And it does. End of story.

(In case you're confused, please know that in C++, #define NULL (0).)

In case you wrote:

T* p = 0;
std::cout << p << std::endl;

then it will display the address 0, (generally in hexadecimal and padded to the pointer size, since this is the preferred way of looking at pointers).

(This is btw the behavior you would get using the C definition of NULL, which is #define NULL ((void*)0).)

Only if you write

char* p = 0;
std::cout << p << std::endl;

are you in trouble. Now you're calling

template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s);

for which the Standard (section 27.7.3.6.4) says:

Requires: s shall not be a null pointer.

When you do pass a null pointer, the rule 17.6.4.9 applies, which states that:

Each of the following applies to all arguments to functions defined in the C++ standard library, unless explicitly stated otherwise. * If an argument to a function has an invalid value (such as a value outside the domain of the function or a pointer invalid for its intended use), the behavior is undefined.

So you're in the land of "undefined behavior". There's no guarantee that failbit gets set and the program continues.


Please note that printf behavior didn't actually depend on the type of NULL. It's the format string "%s" that caused treatment as a string (pointer to NUL-terminated character sequence).

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 2
    Is `NULL` really guaranteed to be defined as `0`? AFAIK, implementations are free to define it e.g. as `0L` – Andy Prowl Jan 25 '13 at 17:16
  • 1
    @AndyProwl True, but can you tell the difference between `cout << 0` and `cout << 0L` at runtime? :) –  Jan 25 '13 at 17:17
  • @Andy: ok, so `std::cout << 0L << std::endl;`. Which also outputs `0\n`. – Ben Voigt Jan 25 '13 at 17:17
  • I'm not questioning whether or not it should output `0`, that's obvious. I was just clarifying a statement that was slightly imprecise. It makes no difference in this case, but it may make a difference in other cases. – Andy Prowl Jan 25 '13 at 17:19
  • 1
    What about the more general case, e.g. `const char *getString() { return NULL; } ... cout << getString()`? – Oliver Charlesworth Jan 25 '13 at 17:19
  • @Oli: That's a different question, clearly. – Ben Voigt Jan 25 '13 at 17:19
  • @BenVoigt: Indeed. But based on the OP's edits, I think that's what's really being asked! – Oliver Charlesworth Jan 25 '13 at 17:20
  • 2
    @arrows: `NULL` is a constant integral expression with value `0`. The type is one of the types allowed for constant integral expressions (e.g. `int`, `unsigned`, `long`, etc) – Ben Voigt Jan 25 '13 at 17:20
  • @Ben Voigt how in general `cout << (const char*) NULL` works in C++? and what is the difference between the definition of NULL in C and C++? I *am* confused, is it defined to be something else other than 0 in C? –  Jan 25 '13 at 17:26
  • @arrows: Now I've answered the three questions you didn't ask. Is that helpful? – Ben Voigt Jan 25 '13 at 17:28
  • +1 for the standard quote – Cornstalks Jan 25 '13 at 17:28
  • @Ben Voigt Yes, indeed helpful –  Jan 25 '13 at 17:33
  • @arrows There's not a fundamental difference between C and C++ here. The C standard gives a little more leeway for non-traditional definitions of `NULL`, but nothing which would make a significant different. – James Kanze Jan 25 '13 at 17:38
  • `There's no guarantee that failbit gets set and the program continues.` And, when it does, failbit is set, so nothing else is accepted into the stream. I covered this somewhere before. – Lightness Races in Orbit Jan 25 '13 at 18:04
  • [Here it is](http://stackoverflow.com/a/7019483/560648) – Lightness Races in Orbit Jan 25 '13 at 18:09
2

printf("%s", str) is not required to handle NULL strings, so by passing NULL you are asking for trouble.

The semantically equivalent statement with IOStreams is:

std::cout << static_cast<char const*>(NULL);

And this is not required to handle NULL string either.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    It's important to remember that `"%s"` requires a `char*` as argument; unlike the C++ version, it doesn't know the type. And `NULL` is _not_ a `char*`; it's an integral type; in the environment in which I currently work, `sizeof(NULL)` and `sizeof(char*)` have different values. – James Kanze Jan 25 '13 at 17:44