-5

我想知道 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)。

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

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

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


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

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

谢谢你帮助我=)

4

5 回答 5

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 中,与许多编程语言一样,函数可以通过函数指针间接调用,因此可能无法通过静态分析轻松计算在给定调用点调用哪个函数。所以,至少在理论上,我会说所有的赌注都没有了。但在实践中,可能是一个安全的假设,一个函数调用最终将返回到紧随其后的点,或者返回到调用堆栈下方的某个位置,可能是操作系统环境。

于 2013-07-15T15:25:08.110 回答
0

向上看setjmp()longjmp()setjmp()在它被调用的地方记录一定数量的本地状态。 longjmp()可能会跨多个功能级别返回到您调用setjmp().

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

于 2013-07-15T14:10:45.837 回答
0

'假设我们正在执行一个调用函数 B() 的函数 A(),我们能否确定在 A() 中对 B() 的调用总是会在调用本身“之后”返回。没有为什么:

“B”可能会引发未在“A”中捕获的异常。

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

'B' 可能会进行一个永远不会返回的阻塞操作系统调用。

于 2013-07-15T15:05:55.407 回答
0

我记得当我需要一种方法来退出一个大程序而不退出时创建这个函数

int     my_exit()
{
  pid_t pid;
  int   i;

  pid = getpid();
  i = kill(pid, SIGQUIT);
  if (i == -1)
    return (-1);
  return (0);
}
于 2013-07-15T14:36:09.877 回答
0

你可以退出一个函数

  • 返回
  • 在其主体的末尾默默地(没有在 a 中明确返回void function()
  • 一个例外
  • 一个longjmp()
  • 内联汇编跳转到某个地址
于 2013-07-15T14:11:16.780 回答