退出功能的可能性

时间:2013-07-15 14:07:59

标签: c++ c function exception return

我想知道C / C ++中的一般话题。 假设我们正在执行一个调用函数B()的函数A(),我们可以确定A()中B()的调用将始终在调用之后“返回”。

在一个更一般的问题中,哪些是退出函数的可能性?

C关键字是(维基百科):auto,break,case,char,const(C89),continue,default,do,double,else,enum(C89),extern,float,for,goto,if,inline (C99),int,long,register,restrict(C99),return,short,signed(C89),sizeof,static,struct,switch,typedef,union,unsigned,void(C89),volatile(C89),while, _Bool(C99),_ Complex(C99),_ Imaginary(C99)。

据我所知,本主题中有趣的是:

  • 中断/继续:用于循环或切换(正如GCC在尝试后告诉我的那样),他们无法退出函数。
  • 转到:标签的范围受功能限制,因此goto无法退出功能
  • 返回:退出一个函数但总是返回调用后的指令。我们对这个很安全。
  • exit()/ abort()函数将结束应用程序。我们不会回到呼叫点,但是......我们根本不会回来。

我认为这是针对C语言的。你认为还有另一种方法可以退出一个函数并且不返回调用点吗?


在C ++中,异常显然不会返回到调用点。他们要么去一个catch区块,要么到达调用函数,寻找一个阻塞块。

据我所知,这将是唯一的案例。

感谢您帮助我=)

5 个答案:

答案 0 :(得分:1)

在标准C(使用setjmp/longjmp)和C ++(使用例外)中,可以有效地返回到更接近CFG根的标记点。实际上,函数可能永远不会返回,但如果它确实返回,则它将到达调用之后的那一点。

但是,setjmp机制的低级特性实际上可以实现协同程序(尽管是以不可移植的方式)。 Posix试图通过强制允许显式堆栈交换的makecontext和朋友来改善这种情况,但这些函数在Posix.1-2001中已弃用并从Posix.1-2008中删除,引用了可移植性问题,建议使用线程代替。尽管如此,还是有许多使用这些功能的协程库允许C程序员享受协同程序的灵活性。

在协程控制流程中,虽然(co)调用之后的执行路径可能是曲折的,但仍然是函数调用永远不会返回或最终返回到紧接的后续点的情况。但是,C库设施的低级特性使得实现更复杂的控制流成为可能,其中给定(共)调用可能例如返回多次。 (我从未在生产代码中看到过这种特殊的异常现象,但我不能声称在全世界范围内只看到了所有生产代码的一小部分:))。

C的gcc扩展允许使用“标签值”,它是指向代码中标签的指针。这些是实数值(类型为void *),因此它们可以作为参数传递给函数。 (gcc手册警告不要这样做。)通过一些逆向工程,可能会编写一个带有一个或多个标签参数的函数,并使用其中一个作为返回点。这显然是对该功能的滥用,可能既不是便携式也不是面向未来的,并且几乎肯定会破坏现有的编码标准。

C库设施的有趣之处在于它实际上是核心语言的一部分的C ++异常,它们确实是函数;在C语言中,与许多编程语言一样,函数可以通过函数指针间接调用,因此通过静态分析可以很容易地计算出在给定调用站点调用哪个函数。所以,至少在理论上,我会说所有的赌注都没有了。但在实践中,可能是一个安全的假设,即函数调用最终将返回到紧接着的点或返回到调用堆栈的某个地方,可能是操作系统环境。

答案 1 :(得分:0)

查找setjmp()longjmp()setjmp()在被调用的位置记录一定量的本地状态。 longjmp()可能会跨越多个功能级别返回到您调用setjmp()的位置。

您可以将它用于C中的原始形式的异常处理。它非常非常少用。

答案 2 :(得分:0)

您可以使用

退出功能
  • 返回
  • 默默地在其身体的末端(没有明确地返回void function()
  • 例外
  • a longjmp()
  • 内联汇编跳转到某个地址

答案 3 :(得分:0)

我记得当我需要一种不退出

退出大程序的方法时创建这个函数
int     my_exit()
{
  pid_t pid;
  int   i;

  pid = getpid();
  i = kill(pid, SIGQUIT);
  if (i == -1)
    return (-1);
  return (0);
}

答案 4 :(得分:0)

'假设我们正在执行一个调用函数B()的函数A(),我们可以确定A()中B()的调用将始终在“调用本身”之后返回。不,因为:

'B'可能引发未在'A'中捕获的异常。

'B'可能包含无限循环。

'B'可能会阻止永远不会返回的OS调用。