打印空指针是否属于未定义行为?

6
当研究这个问题的示例代码时,我认为是未定义行为导致后续使用std::cout无法打印。但事实证明,尝试打印空指针会导致其流状态中设置std::ios_base::badbitstd::ios_base::failbit,这才是它无法操作的真正原因。因此,我现在很好奇打印空指针是否真的是未定义行为。所以这里有我的问题:
  1. 打印空指针是否是未定义行为?如果是,那么流插入器的什么特性会导致这种情况?我相当确定插入器足够聪明,不会对空指针进行解引用。

  2. 我还想知道,为什么在这种情况下(具体地说是badbit),插入器会设置其错误掩码。为什么它不像字符串字面值的终止符一样对待它呢?

我没有可靠的标准,到目前为止,我只找到了一个链接失效的来源。


1
libstdc++可能在不需要的情况下进行额外的nullptr检查。使用clang+libc++构建程序时,程序段错误,但是使用clang+libstdc++则不会。 - Praetorian
2
我非常确定插入器足够聪明,不会对空指针进行解引用。一般来说,C++标准规定编译器必须做什么,而其他任何事情都不必做。在每次调用operator<<(char *)之前进行额外的NULL检查会使正确编码的程序变慢。 - M.M
@MattMcNabb:哈哈,我认为在使用像C ++ I/O流这样极其缓慢的东西时,空指针检查的速度并不重要。 - user541686
密切相关:https://dev59.com/0Ww05IYBdhLWcg3wy052(实际上几乎是重复的) - Lightness Races in Orbit
2个回答

12

basic_ostreamoperator<<(basic_ostream<>&, const char*)函数要求传入的char*参数不能为空指针,因为该函数用于输出指针所指向的字符串。因此,如果将空指针传递给cout,就会发生未定义行为。(参见C++11 27.7.3.6.4/3 "字符插入函数模板")。

然而,basic_ostreamoperator<<(basic_ostream<>&, const void*)函数只是输出指针的值,因此使用该重载时空指针也能正常工作。


6
如果您通过[ostream.inserters.character]引用标准而不是使用27.7.3.6.4,则它更有可能在不同版本中仍然是一个有效的参考,因为这些版本可能已经重新编号了章节或部分。 - M.M

2

gcc ostream.tcc的第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只是进行了一项标准没有保证的检查,这没关系,因为它本来就是未定义的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接