如果没有选项,标准习语是:
int returnCode = 0;
void
processFile( std::string const& filename )
{
if ( filename == "-" ) {
process( std::cin );
} else {
std::ifstream in( filename.c_str() );
if ( !in.is_open() ) {
std::cerr << argv[0] << ": cannot open " << filename << std::endl;
returnCode = 1;
} else {
process( in );
}
}
}
int
main( int argc, char** argv )
{
if ( argc == 1 ) {
processFile( "-" );
} else {
for ( int i = 1; i != argc; ++ i ) {
processFile( argv[i] );
}
}
std::cout.flush()
return std::cout ? returnCode : 2;
}
然而,有许多变体。我发现自己经常这样做,以至于我编写了一个MultiFileInputStream
类,其 (template> 构造函数采用一对迭代器;然后它执行或多或少与上面相同的代码。(所有重要的代码像往常一样,在相应的streambuf。)类似地,我有一个类来解析选项(一旦解析了选项,它看起来就像一个不可变std::vector<std::string>
的。所以上面会变成:
int
main( int argc, char** argv )
{
CommandLine& args = CommandLine::instance();
args.parse( argc, argv );
MultiFileInputStream src( args.begin(), args.end() );
process( src );
return ProgramStatus::instance().returnCode();
}
(ProgramStatus
是另一个有用的类,它处理错误输出和返回码。std::cout
当你调用它时刷新和调整错误码returnCode()
。)
我确信任何编写 Unix 过滤器程序的人都开发过类似的类。
关于问题 2:sync_with_stdio
是 的静态成员std::ios_base
,因此您可以在没有对象的情况下调用它:
std::ios_base::sync_with_stdio( false );
。我发现这不太容易误导,因为调用会影响所有iostream 对象。如果 IO 处理是一个阻塞点,无论如何都要做,但大多数时候,我不打扰。此类程序很少需要任何类型的优化。(请注意,如果你调用了
sync_with_stdio
,那么你不应该使用任何 C 风格的 IO。但我看不出有任何理由使用它。)
关于问题 3:错误消息std::cerr
总是转到 。您还希望确保返回非零返回码,即使错误不是致命的。就像是:
myprog file1 > tmp && mv tmp file1
都是常见的,如果你有一些问题,并且不生成输出,如果你不返回非零错误代码,那将是一场灾难。(这就是为什么我总是刷新然后检查 . 的状态std::cout
。很久很久以前,我的程序的用户做了上述操作,文件非常大,磁盘已满。之后就没有那么满了。从那时起:总是 flush std::cout
,并检查它是否有效,然后返回 OK。)