Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 更好的方法是将(退出故障)返回到main还是在函数中退出(退出故障)?_C - Fatal编程技术网

C 更好的方法是将(退出故障)返回到main还是在函数中退出(退出故障)?

C 更好的方法是将(退出故障)返回到main还是在函数中退出(退出故障)?,c,C,我有一个关于c语言中正确的程序结构的基本问题 假设我的主函数调用其他几个函数来配置特定的硬件(如以太网卡),并且这些函数中的每一个都调用更基本的函数来处理以太网卡上更具体的配置 较低级别的函数都有返回值,用于指定它们是否已成功完成。将这种范式一直延续到main是最合适的吗 例如,如果我的一个低级功能失败,我应该执行以下操作吗 check its return value --> return to calling function --> check its return value

我有一个关于c语言中正确的程序结构的基本问题

假设我的主函数调用其他几个函数来配置特定的硬件(如以太网卡),并且这些函数中的每一个都调用更基本的函数来处理以太网卡上更具体的配置

较低级别的函数都有返回值,用于指定它们是否已成功完成。将这种范式一直延续到main是最合适的吗

例如,如果我的一个低级功能失败,我应该执行以下操作吗

check its return value --> return to calling function --> check its return value --> return to calling function ... 
一路回到梅因

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

我非常感谢你的帮助

在我看来,直接从失败的函数调用
exit(exit\u FAILURE)
是可以的。如果需要一些清理,那么我将使用
atexit()

#包括
无效退出(int状态);
exit()函数导致正常进程终止。。。
调用在atexit(3)和on_出口(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,当以这种方式用于错误处理时,goto远非邪恶。

这里有多个独立的问题

至于是应该向上传播错误,还是在检测到问题时调用
exit(exit\u FAILURE)
,我通常建议向上传播错误。如果低级代码向上传播错误,则高级代码可能会尝试处理错误(例如,向用户报告错误、重试、尝试其他配置等)。如果低级代码退出,高级代码就没有机会处理它。(另一方面,更高级别的代码必须准备好做一些适当的事情,而不是仅仅假设没有错误就继续执行。)

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

至于您是应该从
main
返回还是致电
exit
,这取决于您自己。为了实现超级便携性,我建议调用
exit
,并根据需要选择exit\u SUCCESS或exit\u FAILURE。但是,通常情况下,如果成功,
返回0
,如果失败,
返回非零。后一种做法在一些晦涩难懂、大多是死气沉沉的操作系统上无法很好地工作,这些操作系统使用的是死气沉沉的编译器。在任何情况下,我都不会
main
返回EXIT\u SUCCESS

您所说的是哪种故障(严重性)?
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);
   }