最好返回(EXIT_FAILURE)到main或退出(EXIT_FAILURE)函数?

时间:2014-04-17 16:48:56

标签: c

我对c。

中正确的程序结构有一个基本的问题

让我们说我的主函数调用其他几个函数来配置一个特定的硬件(如以太网卡),并且每个函数都调用更多基本函数来处理该以太网卡上更具体的配置

较低级别的函数都具有返回值,用于指定它们是否已成功完成。继续这种范式一直回到主要方面是否最合适?

例如,如果我的一个较低级别的函数失败,我应该执行以下操作吗?:

check its return value --> return to calling function --> check its return value --> return to calling function ... 

一直回到主?

或者让main假设一切正常运行(不考虑它调用的函数的返回值)并返回0更有意义;然后从较低级别的函数调用exit(EXIT_FAILURE)?

我非常感谢帮助。

3 个答案:

答案 0 :(得分:3)

对于学术界的申请,我认为不重要。     。 但是,对于生产(企业)应用程序,我(30年)的经验是:

1)  Never call exit() unless it's a last resort, where the user needs to 
    contact the application developer to resolve an unanticipated condition.

2)  In order to ensure maintainability, functions should not contain more
    than one return statement.  

我生产的所有功能(用于企业生产环境)都有类似的流程:

int SomeEnterpriseQualityFunction(
      SOME_TYPE1_T   I__someValueBeingPassedIntoTheFunction,
      ...
      SOME_TYPE2_T  *IO_someValueBeingModifiedByTheFunction,
      ...
      SOME_TYPE3_T **_O_someValueBeingReturnedByTheFunction
      )
   {
   int rCode=0;
   int someFileHandle=(-1);
   void *someMemory = NULL;
   SOME_TYPE3_T *someValueBeingReturnedByTheFunction=NULL;


   /* Validate user input parameters */
   if( /*I__someValueBeingPassedIntoTheFunction is out of range */)
      {
      rCode=ERANGE;
      goto CLEANUP;
      }

   if( NULL == IO_someValueBeingModifiedByTheFunction )
      {
      rCode=EINVAL;
      goto CLEANUP;
      }       

   /* Acquire resources */
   someFileHandle=open(/*someFileName, mode, etc.*/);
   if((-1) == someFileHandle)
      {
      rCode=errno;
      goto CLEANUP;
      }

   someMemory=malloc(/* bytesToMalloc */);
   if(NULL == someMemory)
      {
      rCode=ENOMEM;
      goto CLEANUP;
      }

   /* Actual work done here. */
   ....
   if(/* Successfully finished work at this point... */)
      goto RESULT;
   ...
   ...

   /* Return results to caller here. */
RESULT:
   if(_O_someValueBeingReturnedByTheFunction);
      {
      *_O_someValueBeingReturnedByTheFunction = someValueBeingReturnedByTheFunction;
      someValueBeingReturnedByTheFunction = NULL;
      }

   /* Release acquired resources. */
CLEANUP:
   if(someValueBeingReturnedByTheFunction)
      {
      int rc= /* Clean-up someValueBeingReturnedByTheFunction related resources, 
                 since the caller didn't need it. */
      if(0==rCode)
         rCode=rc;
      }

   if(someMemory)
      free(someMemory);

   if((-1) != someFileHandle)
      {
      if((-1) == close(someFileHandle) && 0 == rCode)
         rCode=rc;
      }

   return(rCode);
   }

而且,无论你的教师对goto的看法是什么,当他们以这种方式用于错误处理时,他们都远非-'。

答案 1 :(得分:1)

在我的意见中,从失败的函数调用exit( EXIT_FAILURE )是正常的。如果需要进行一些清理,那么我会使用atexit()

来自http://linux.die.net/man/3/exit

#include <stdlib.h>
void exit(int status);

The exit() function causes normal process termination ...

All functions registered with atexit(3) and on_exit(3) are called,
in the reverse order of their registration. 

答案 2 :(得分:0)

这里有多个不同的问题。

至于你是否应该传播错误或者只是在检测到问题的时候调用exit(EXIT_FAILURE),我通常会建议传播错误。如果低级代码向上传播错误,则保留了更高级代码可能尝试处理错误的可能性(例如,向用户报告,重试,尝试不同的配置等)。如果低级代码失效,则更高级别的代码没有机会处理它。 (另一方面,更高级别的代码必须准备好某些适当的,而不是只是假设没有错误继续。)

至于那些错误值应该是什么,我通常建议您定义自己的返回状态类型(例如,作为枚举)。 EXIT_FAILURE和EXIT_SUCCESS旨在作为exit的输入,您应将它们视为不透明值。例如,不要假设EXIT_SUCCESS为0。

至于您是应该从main返回还是致电exit,这取决于您。为了超级超便携,我建议根据需要使用EXIT_SUCCESS或EXIT_FAILURE调用exit。但是,通常只需return 0表示成功,或return nonzero表示失败。后一种做法在一些模糊的,主要是死机操作系统上运行效果不佳。无论如何,我永远不会return EXIT_SUCCESS来自main