关于c ++:退出函数的可能性

Possibilities to quit a function

我在想一个关于C/C++的一般性话题。假设我们正在执行一个调用函数b()的函数a(),我们能确保a()中b()的调用总是在调用本身之后返回吗?

在更一般的问题中,退出函数的可能性是什么?

c关键字是(wikipedia):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、ool(c99)、u complex(c99)),想象的(c99)。

据我所知,这一主题的一个有趣之处是:

  • 中断/继续:在循环或开关中使用(正如我在尝试后被GCC告知的那样),它们不能退出函数。
  • goto:标签的范围受函数限制,因此goto不能退出函数
  • 返回:可以退出函数,但总是在调用后返回到指令。这个我们很安全。
  • exit()/abort()函数将结束应用程序。我们不会回到呼叫点,但是……我们不会回来的。

我想这是C语言。您认为还有其他方法可以退出一个函数而不返回调用点吗?

在C++中,异常显然不会返回到调用点。它们要么转到catch块,要么到达调用函数,查找catch块。

据我所知,这是唯一的情况。

谢谢你帮助我=)


在标准C(使用EDCOX1〔7〕)和C++(使用异常)时,有可能有效地返回接近CFG根的标记点。实际上,一个函数可能永远不会返回,但如果它确实返回,它将到达调用之后的点。

然而,setjmp机制的低级性质实际上使实现协同程序成为可能(尽管是以非便携式方式)。posix试图通过强制makecontext和friends(允许显式的堆栈交换)来改善这种情况,但是posix.1-2001中不推荐使用这些函数,并从posix.1-2008中删除了这些函数,引用了可移植性问题,并建议使用线程。尽管如此,仍有许多协程库在使用中,它们使用这些特性使C程序员能够享受协程的灵活性。

在协程控制流中,虽然(co)调用后面的执行路径可能是曲折的,但函数调用始终不会返回或最终返回到紧随其后的点。但是,C库设施的低级特性使实现更复杂的控制流成为可能,例如,在这种控制流中,给定的(co)调用可能返回多次。(我从来没有在生产代码中看到过这种特殊的异常情况,但是我不能声称在世界上看到过所有生产代码中的一小部分。)

gcc对c的扩展允许使用"label values",它是代码中标签的指针。这些是实值(类型为void *),因此它们可以作为参数传递给函数。(GCC手册警告不要这样做。)对于一些逆向工程,可能可以编写一个函数,它接受一个或多个标签参数,并将其中一个参数用作返回点。这显然是对特性的滥用,可能既不是可移植的,也不是未来的证明,而且几乎肯定会破坏现有的任何编码标准。

C库设施的有趣之处在于,C++实际上是函数的一部分,而不是C++异常,它们实际上是函数;在C语言中,与许多编程语言一样,函数可以通过函数指针间接调用,以便通过静态分析而不容易计算函数。正在给定的呼叫站点调用。所以,至少在理论上,我认为所有的赌注都结束了。但在实践中,可能是一个安全的假设,即函数调用最终将返回到紧随其后的点,或者返回到调用堆栈的某个位置,可能是操作系统环境。


假设我们正在执行一个调用函数b()的函数a(),我们能否确保a()中b()的调用总是在"调用本身"之后返回。不,因为:

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

"b"可以包含无限循环。

"b"可能会发出一个永远不会返回的阻塞操作系统调用。


我记得当我需要一种不退出就退出一个大程序的方法时,我就创建了这个func。

1
2
3
4
5
6
7
8
9
10
11
int     my_exit()
{
  pid_t pid;
  int   i;

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


您可以退出一个函数

  • 返回
  • 在它的身体末端安静地(没有在一个void function()中明确返回)
  • 例外
  • longjmp()
  • 内联程序集跳转到某个地址


查看setjmp()longjmp()setjmp()记录了它所称的地方政府的一定数量。longjmp()可能会在几个功能级别上返回到您称之为setjmp()的位置。

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