1

我想使用 longjmp 来模拟 goto 指令。我有一个包含结构类型元素(int、float、bool、char)的数组 DS。我想跳转到标有“lablex”的地方,其中 x 是 DS[TOP].int_val。我该如何处理?

示例代码:

...
jmp_buf *bfj;
...
stringstream s;s<<"label"<<DS[TOP].int_val;
bfj = (jmp_buf *) s.str();
longjmp(*bfj,1);

但是当我认为它有问题时,我该怎么办?

错误:

output.cpp:在函数'int main()'中:

output.cpp:101:错误:从类型 'std::basic_string, std::allocator >' 到类型 '__jmp_buf_tag (*)[1]' 的无效转换</p>

4

5 回答 5

5

You probably don't want to use longjmp at all but I hate it when people answer a question with "Why would you want to do that?" As has been pointed out your longjmp() usage is wrong. Here is a simple example of how to use it correctly:

#include <setjmp.h>

#include <iostream>

using namespace std;

jmp_buf jumpBuffer;  // Declared globally but could also be in a class.

void a(int count) {
  // . . .
  cout << "In a(" << count << ") before jump" << endl;
  // Calling longjmp() here is OK because it is above setjmp() on the call
  //   stack.
  longjmp(jumpBuffer, count);  // setjump() will return count
  // . . .
}


void b() {
  int count = 0;

  cout << "Setting jump point" << endl;
  if (setjmp(jumpBuffer) == 9) return;
  cout << "After jump point" << endl;

  a(count++);  // This will loop 10 times.
}


int main(int argc, char *argv[]) {
  b();

  // Note: You cannot call longjmp() here because it is below the setjmp() call
  //  on the call stack.

  return 0;
}

The problems with your usage of longjmp() are as follows:

  1. You don't call setjmp()
  2. You haven't allocated the jmp_buf either on the stack or dynamically. jmp_buf *bfj is just a pointer.
  3. You cannot cast a char * to jmp_buf * and expect it to work. C++ not a dynamic language it is statically compiled.

But really, it is very unlikely that you should be using longjmp() at all.

于 2010-06-21T20:15:29.107 回答
5

使用 longjump 的正常方法是与此处所述的 setjump() 结合使用。您似乎想像通常使用 switch-case 或虚拟函数一样制作一个跳转表。

无论如何,字符串(运行时)无法访问代码中的标签(编译时),因此这已经是您的第一个问题。你真的需要找出你想跳转到的地址,我最好的猜测是将 setjump() 放在你的标签所在的位置。

于 2010-06-21T18:27:43.257 回答
2

你完全失败了 C++。首先,goto 是不好的,而且不适合外行 - 有一个原因,即 for, while, break, continue 等存在。其次,您试图将字符串转换为标识符,这在运行时是不可能的,除非您自己编写代码。第三,您正在.. 尝试将 const char* 转换为 jmp_buf*?什么?

除此之外,C++ 确实有 goto。但是如果你想在给定一个 int 的情况下跳转,那么你将不得不切换它,例如

switch (DS[TOP].int_val) {
case 1:
    goto label1;
    break;
case 2:
    goto label2;
    break;
default:
    throw std::runtime_error("Unrecognized label!");
}
于 2010-06-21T18:25:52.700 回答
0

听起来你想要一个函数指针:


((void(*)(void))*((int *)DS[TOP].int_val))();

这会将 DS[TOP].int_value 视为地址并跳转到它。如果您想跳转到 DS[TOP].int_value 所在的位置,您可以:


((void(*)(void))*((int *)&DS[TOP].int_val))();

无论哪种方式,丑陋,丑陋的代码。但它应该做你想做的事。

于 2010-06-21T18:47:16.153 回答
0

调用 setjmp() 时,系统有效地获取调用和参数堆栈的快照。在用户代码退出调用 setjmp() 的块之前,此快照将保持有效;如果使用该快照调用 longjmp(),则执行将恢复,就好像 setjmp() 第一次返回一样,除了返回零,它将返回传递给 longjmp() 的第二个参数。请务必注意,使用无效快照调用 longjmp() 可能会产生非常糟糕的效果。在某些系统中,这样的无效调用可能“看起来”有效,但会破坏系统,导致系统随后崩溃。

虽然 setjmp()/longjmp() 有时适用于纯 C 程序,但让 C 程序调用 setjmp() 来创建快照,然后调用一些 C++ 代码,而后者又调用 longjmp() 以返回到该快照,这是一种灾难的秘诀。几乎所有想要这样做的情况都可以使用异常更好地处理。

于 2010-06-21T22:21:48.210 回答