如何(计算)在c++中跳转和跳远

How to (computed) goto and longjmp in C++?

本文关键字:c++ 计算 如何      更新时间:2023-10-16

我通常不写c++代码,但是我的一个奇怪的计算机科学朋友厌倦了看我精彩的FORTRAN程序,并挑战我用c++重写其中一个程序,因为他更喜欢我的c++代码。(我们在这里下注。)确切地说,它需要在现代c++编译器中可编译。也许他讨厌一个好主意。h -我不知道。

现在我意识到用c++有非常好的写作方式,但我想在这里取得个人胜利,我试图使我的c++版本尽可能地像fortran那样。额外的好处是,当我转换代码时,这可能会节省我一些时间和精力。

如此!这给我带来了以下相关查询:

在转到

:

  1. 你是如何工作的?
  2. c++中gotos的约束是什么?
  3. 对范围有什么顾虑吗?(我将尽可能尝试全局范围,但你永远不会知道。)
  4. 如果我使用GCC扩展到一个空指针数组,是否有任何关于未定义行为等的新问题?


在longjmp :

  1. 你如何安全地使用跳远?
  2. c++中长距离跳跃的约束是什么?
  3. 它对范围有什么作用?
  4. 有没有一些特定的时刻,看起来跳远应该是安全的,但实际上不是,我应该注意?
  5. 我如何用跳远模拟计算的goto ?
  6. 如果我的程序中只有一个函数,使用longjjump比goto有任何切实的好处吗?

现在我主要关心的是使计算goto工作。看起来我可能会使用longjmp来完成这项工作,因为void指针数组不是c++标准的一部分,而是GCC特定的扩展。

我要咬牙接受投票。

我非常怀疑你的朋友会发现用c++编写的Fortran更容易阅读(如果你大量使用goto和longjmp,这实际上是你会得到的),他甚至可能会发现更难理解。c++语言与Fortran有很大的不同,我真的不认为你应该尝试从Fortran直接转换到c++。这只会使c++更难维护,你最好还是继续使用现有的代码库。

goto:您设置一个标签(my_label:),然后使用goto命令goto my_label;,这将导致您的程序流在goto语句后面执行。您不能跳过变量的初始化或在函数之间跳转。你不能创建一个goto目标数组,但是你可以创建一个对象或函数指针数组来跳转。

longjmp:如果你只有一个功能,没有理由更喜欢longjmp而不是goto。但是如果你只有一个函数,你真的不需要写c++从长远来看,你只需要维护你的Fortran语言就可以了。

你会得到很多关于使用goto的仇恨。通常情况下,我会紧跟潮流,但在这种特殊情况下,对我来说这听起来更像是代码高尔夫。

使用goto将指令指针移动到代码中的"label",这是一个c++标识符,后面跟着一个冒号。下面是一个工作程序的简单示例:

#include <iostream>
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    int i = 0;
step:
    cout << "i = " << i;
    ++i;
    if( i < 10 )
        goto step;
}

在本例中,step:是标签。

需要考虑上下文

  • 只能对当前功能内的标签进行goto
  • 如果你的goto跳过变量的初始化,你可能会调用未定义行为(代码可以编译,但你不能确定它实际上会做什么)。
  • 不能将goto转换为try块或catch处理程序。但是,您可以 goto try块中取出

如果满足其他要求,您可以使用指针等"goto"。如果所讨论的指针在调用站点和分支站点的范围内,则没有问题。

我想这份参考资料已经包含了你要找的大部分信息。

goto

longjmp

计算goto——> switch

实际上,它们共享一个(通用的,但不是通用的)底层实现,即跳转表

如果我理解了原来的问题,这个问题实际上是一个有趣的问题。把这个问题重新表述一下(我认为这是一个等价的问题):"如何在C语言中执行FORTRAN计算的goto ?"

首先我们需要知道什么是计算式goto:这里有一个解释链接:http://h21007.www2.hp.com/portal/download/files/unprot/fortran/docs/lrm/lrm0124.htm.

计算的GOTO的一个例子是:

    GO TO (12,24,36), INDEX

其中12、24、36为语句数。(C语言的标签可以作为等价的,但不是唯一的等价的东西。)

其中INDEX是一个变量,但可能是公式的结果。

下面是一种(但不是唯一的)在C中做同样事情的方法:
int SITU(int J, int K)
{
int raw_value = (J * 5) + K;
int index = (raw_value % 5) - 1;
return index;
}

int main(void)
{
int J = 5, K= 2;
// fortran computed goto statement: GO TO (320,330,340,350,360), SITU(J,K) + 1
switch (SITU(J,K) + 1)
{
case 0: // 320
    // code statement 320 goes here
    printf("Statement 320");
    break;
case 1: // 330
    // code statement 330 goes here
    printf("Statement 330");
    break;
case 2: // 340
    // code statement 340 goes here
    printf("Statement 340");
    break;
case 3: // 350
    // code statement 350 goes here
    printf("Statement 350");
    break;
case 4: // 360
    // code statement 360 goes here
    printf("Statement 360");
    break;
}
printf("nPress Entern");
getchar();
return 0;
}

在这个特殊的例子中,我们看到你不需要C的goto来实现FORTRAN计算的goto!

Longjmp可以让您摆脱信号处理程序,这可能很好-但它会增加一些混乱,因为它不会重置它在setjmp行之前长跳转到定义的函数中的自动(基于堆栈的)变量。

有一个名为Labels as Values的GCC扩展,它将帮助您编写高尔夫代码,本质上是给您计算goto。当然,您可以自动生成标签。您可能需要这样做,因为您不知道每行将生成多少字节的机器码。