检查 C 和 C++ 中的输出错误

Checking Output Errors in C and C++

我写了这个简单的程序。我知道 C 中的 printf() 函数 returns 成功打印的字符总数因此以下 C 程序工作正常,因为任何非零值在 C 中被评估为 true

#include <stdio.h>

int main(void)
{
   if (printf("C"))
   return 0;
}

但为什么下面的 C++ 程序可以正常编译和运行?如果 cout 是对象而不是函数,那么为什么程序会给出预期的输出?

#include <iostream>
using namespace std;

int main() {
    if (cout << "C++")
    // your code goes here
    return 0;
}
std::cout << "C++";

是对 std::operator<<(std::cout, const char*) 的函数调用,returns 是对 std::cout 的引用,可转换为 bool。如果 std::cout 上没有发生错误,它将评估为 true

因为这样写是一样的

cout << "C++";
if(cout){
//do whatever
}

它只是将 "C++" 写入 cout 并检查您的流是否仍然打开。

<< 运算符 returns cout。这就是为什么您可以像这样链接 << 运算符:

std::cout << "Hello" << " " << "C++" << " " << "World!" << std::endl;

返回的 cout 将隐式转换为 if.

中的值 true

我不太确定你想做什么,但假设你希望你的程序成功退出,当且仅当打印成功时,你应该把它写在 C:

#include <stdlib.h>
#include <stdio.h>

int
main()
{
    if(printf("C") < 0)
      return EXIT_FAILURE;
    return EXIT_SUCCESS;
}

原因是printf会return一个负数来报错,-1也被认为是“真”

相应的 C++ 程序应该如下所示:

#include <cstdlib>
#include <iostream>

int
main()
{
  if (!(std::cout << "C++"))
    return EXIT_FAILURE;
  return EXIT_SUCCESS;
}

之所以可行,是因为在 std::cout return 上调用运算符 << 是对流 本身 的引用,这也是为什么像

这样的东西
std::cout << "You've got " << 99 << " points" << std::endl;

工作。每次调用 return 都是对 std::cout 的引用,下一次调用将在该引用上执行。

现在,std::cout 派生的 std::basic_ios 定义了一个 conversion operator。从 C++11 开始,这被声明为

explicit operator bool() const;

这意味着如果在布尔上下文中评估流,例如 if 语句中的条件,它将转换为 boollinked page 底部的 table 显示在什么条件下 returned bool 将是 truefalse。总结:它将 return true 除非流上发生错误。

在 C++11 之前(当我们没有 explicit 运算符时),一个 void * 指针被 return 编辑为非 NULL 如果并且仅当流上没有错误发生时。同样,可以在布尔上下文中评估 void * 指针。

请注意,在上面显示的两个程序中,测试可能表明成功,但输出可能仍然失败。这样做的原因是输出通常在程序内部缓冲,只有收集到足够的输出才会要求操作系统实际执行输出。您可以随时请求 flush 以实现 now。在 C 中,您将在相应的 FILE * 指针上调用 fflush

#include <stdlib.h>
#include <stdio.h>

int
main()
{
    if(printf("C") < 0 || fflush(stdout) < 0)
      return EXIT_FAILURE;
    return EXIT_SUCCESS;
}

在 C++ 中,您可以使用 std::flush 常量。

#include <cstdlib>
#include <iostream>

int
main()
{
  if (!(std::cout << "C++" << std::flush))
    return EXIT_FAILURE;
  return EXIT_SUCCESS;
}

如果你还想要一个换行符,你可以使用std::endl。写作

std::cout << "hello, world\n" << std::flush;

和写

的效果差不多
std::cout << "hello, world" << std::endl;

但是请注意,出于性能原因使用输出缓冲,因此如果您在每个输出语句后例行刷新缓冲区,则很可能会降低程序的性能。

最后,在 C++ 中,您还可以要求流在发生错误时抛出异常。由于 I/O 错误不应在正常操作期间发生,并且重复检查错误会使您的代码混乱,因此这可能会派上用场。

#include <cstdlib>
#include <iostream>

int
main()
{
  std::cout.exceptions(std::ifstream::failbit);
  try
    {
      std::cout << "C++" << std::flush;
      return EXIT_SUCCESS;
    }
  catch (const std::ios_base::failure &e)
    {
      return EXIT_FAILURE;
    }
}

如果您想测试您的程序是否为失败 I/O 报告正确的退出状态,您可以尝试将标准输出通过管道传输到 POSIX 系统上的 /dev/full/dev/full 是一个特殊的文件,它假装 因为超出了文件系统的容量而无法向其中写入任何内容。