C or C++ Return Status
编写返回一个表示状态代码的int的C或C++函数的最佳实践是什么?
具体来说,我想知道客户机的用法,但欢迎使用其他提示。
例如,我可以这样写吗:
1 2 3 | int foo() { return 0; // because everything was cool } |
然后像这样使用?
1 2 3 4 5 | if (foo()) { // what to do if false, e.g. non-zero, e.g. not OK } else { // what to do if true, e.g. zero, e.g. OK } |
这应该是可行的,因为最佳实践通常规定,状态代码
但是,这不太好,对吧:
1 2 3 4 5 | if (!foo()) { // what to do if true } else { // what to do if false } |
我们在C中使用这个,在我工作的地方:
1 2 3 4 | int err = foo(); if (err) { // armageddon } |
赋值和if可以组合,但是如果函数调用更复杂,它会变得更混乱,有些人会被条件中的赋值所迷惑(gcc讨厌它)。
对于C++,如果有可用的话,我更喜欢例外。
编辑:我建议成功时返回0,错误时返回任何其他值。这就是Unix命令行实用程序所做的。
如果您真的想用这种方式使用状态代码,请将它们与描述状态代码意图的
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | enum { kSuccess = 0, kFailure = -1, } function foo() { return kSuccess; } if (kSuccess == foo()) { // Handle successful call to foo } else { // Handle failed call to foo } |
这样,目的是明确的,当有人想要在将来使用或维护您的代码时,不存在容易出错的猜测。
1 2 3 4 5 | if (foo()) { // what to do if false } else { // what to do if true } |
这种方法的问题是过度嵌套。假设您有三个要调用的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 | if(foo1()) { if(foo2()) { if(foo3()) { // the rest of your code } else { // handle error } } else { // handle error } } else { // handle error } |
要解决过量嵌套问题,请反转返回值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | if(!foo1()) { // handle error return; } if(!foo2()) { // handle error return; } if(!foo3()) { // handle error return; } |
这个解决方案遇到了另一个问题。它混合了程序逻辑和错误处理代码。这使一切变得复杂。理想情况下,您希望程序逻辑和错误处理分开。这个问题可以用goto解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | if(!foo1()) goto error1; if(!foo2()) goto error2; if(!foo3()) goto error3; return; error1: // handle error return; error2: // handle error return; error3: // handle error return; |
干净多了。
此外,goto还可以解决资源分配问题。有关更多详细信息,请参阅EliBendersky在C中使用Goto进行错误处理。
最好的做法是记录您的代码,以便您和其他人在执行错误检查时可以快速查找返回代码。
返回状态应该在接口中定义,并为调用方所知。一些失败时返回0(因为很容易检查
没有法律或标准,每个接口定义自己的约定。在C++中使用异常。
只需跳上另一个适合您情况的选项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | enum fooret { GOOD, BAD, UGLY, WORSE }; fooret foo(); // defined elsewhere switch(foo()) { case BAD: case UGLY: // maybe a recoverable failure(s)... // take appropriate actions break; case WORSE: // maybe non-recoverable break; case GOOD: // successful, take appropriate actions break; } |
1 2 3 4 5 6 7 8 9 10 | int foo() { try{ ... return 1 } catch { return 0; // because everything was cool } } |
我首先将所有内容包装在一个try/catch块中。另外,它可能会使更多的场景返回布尔值,而不是使用和int。在if语句中进行测试时,这只是稍微直观一点。