检查 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
语句中的条件,它将转换为 bool
。 linked page 底部的 table 显示在什么条件下 returned bool
将是 true
或 false
。总结:它将 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
是一个特殊的文件,它假装 因为超出了文件系统的容量而无法向其中写入任何内容。
我写了这个简单的程序。我知道 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
语句中的条件,它将转换为 bool
。 linked page 底部的 table 显示在什么条件下 returned bool
将是 true
或 false
。总结:它将 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
是一个特殊的文件,它假装 因为超出了文件系统的容量而无法向其中写入任何内容。