为什么 std::cout 输出在发送 NULL 后完全消失
我花了一段时间才弄清楚为什么一些 cout 输出似乎消失在以太中.罪魁祸首:
std::cout<<这条线显示得很好"<<std::endl;const char* some_string = a_function_that_returns_null();如果(some_string == 0)std::cout<<"让我们检查 some_string 的值:" <<some_string <<std::endl;std::cout<<此行和之后的任何 cout 输出都不会显示"<<std::endl;
上面代码片段的输出将是:
这一行显示得很好让我们检查 some_string 的值:
因此,将 NULL 输入 cout 之后将禁用所有输出.为什么?以及如何修复它?
这不会一直发生 - 具有相同代码的同事会获得所有预期的输出.如果你想知道为什么我不能用 if 语句阻止将 NULL 输入 cout:我正在一个大型代码库中工作,不知道还有什么地方会发生这种情况!我所知道的是,我提出的 cout 声明从未出现过.
<小时>更多信息:
a_function_that_returns_null()
实际上是 getenv("HOST")
.我通过 echo $HOST
在命令行上检查了 HOST 变量是否为空.如果我执行 export HOST=
(bash 风格),输出都在那里.在修改 HOST 变量之前,我不知道 HOST 变量最初包含什么,也不知道 getenv
最初返回什么;我只知道 (some_string == 0)
是真的.
const char* some_string = a_function_that_returns_null();
你的意思是它真的返回一个空指针吗?
[2003: 27.6.2.5.4]:
templatebasic_ostream<char,traits>&运算符<<(basic_ostream& out, const char* s);
3. 要求:s 非空.
然后流式some_string
是未定义的行为;您不能取消引用指针来获取字符串 —甚至是空的――如果指针无效.
这不会一直发生 - 使用相同代码的同事获得所有预期输出
UB 导致不可靠的症状.您并不总是崩溃可能有点令人惊讶,因为大多数现代操作系统都强调在您尝试取消引用空指针时总是 SIGSEGV
ing.
然而,从 C++ 的角度来看,任何事情都可能发生;在您的特定情况下,您的标准库实现很可能正在检查空指针并在流上设置错误标志,而不是尝试取消引用指针.这是它的特权.
(这也可能是您的后续流操作失败的原因:当设置了错误标志时,尝试写入流没有任何作用.)
例如,GCC 4.6.0 附带的 libstdc++,尽管 命名 s != 0
作为前提,确实 这样做:
00325 if (!__s)00326 __out.setstate(ios_base::badbit);00327 其他
但是,您必须不要依赖这种行为;它可以随时改变!
<小时>所以,不要这样做.如果确实需要,请传输一个有效但为空的字符串.
std::string
有什么问题?
It took me a while to figure out why some cout output seem to disappear into the ether. The culprit:
std::cout<< "This line shows up just fine" << std::endl;
const char* some_string = a_function_that_returns_null();
if (some_string == 0)
std::cout<< "Let's check the value of some_string: " << some_string << std::endl;
std::cout<< "This line and any cout output afterwards will not show up" << std::endl;
The output from the snippet above will be:
This line shows up just fine
Let's check the value of some_string:
So feeding a NULL into cout will disable all output afterward. Why? And how to fix it?
This doesn't happen all the time - a co-worker with the same code gets all the expected output. And in case you wonder why I can't just prevent feeding NULL into cout with a if statement: I'm working in a large codebase, and don't know where else this happens! All I know is the cout statements I put never showed up.
More info:
a_function_that_returns_null()
is actually getenv("HOST")
. I checked on the commandline via echo $HOST
that the HOST variable is empty. If I do export HOST=
(bash flavor), the output are all there. I have no idea what the HOST variable contains initially nor what getenv
returns initially when before I modify the HOST variable; all I know is (some_string == 0)
is true.
const char* some_string = a_function_that_returns_null();
Do you mean that it literally returns a null pointer?
[2003: 27.6.2.5.4]:
template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s);
3. Requires: s is non-null.
Then streaming some_string
is Undefined Behaviour; you cannot dereference a pointer to get a string — even an empty one — if the pointer is not valid.
This doesn't happen all the time - a co-worker with the same code gets all the expected output
UB leads to unreliable symptoms. That you don't always get a crash can be slightly surprising because most modern OSs make a point of always SIGSEGV
ing when you try to dereference a null pointer.
However, from a C++ point of view, anything can happen; in your particular case, your standard library implementation may well be checking for a null pointer and setting an error flag on the stream instead of attempting to dereference the pointer. That is its prerogative.
(It's also probably why your subsequent stream operations are failing: attempting to write to a stream does nothing when there's an error flag set.)
For example, the libstdc++ that ships with GCC 4.6.0, despite naming s != 0
as a precondition, does do this:
00325 if (!__s)
00326 __out.setstate(ios_base::badbit);
00327 else
However, you must not rely on this behaviour; it could change at any time!
So, simply don't do this. Stream a valid, but empty, string if you really must.
And what's wrong with std::string
?
相关文章