问题与longjmp

时间:2010-06-21 18:17:28

标签: c++ longjmp

我想使用longjmp来模拟goto指令。我有一个包含struct类型元素的数组DS(int,float,bool,char)。我想跳到标有“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&gt;'类型无效转换为'__jmp_buf_tag(*)[1]'

5 个答案:

答案 0 :(得分:5)

使用longjump的常规方法是与here所述的setjump()组合。您似乎想像通常使用switch-case或使用虚函数一样进行跳转。

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

答案 1 :(得分:5)

你可能根本不想使用longjmp,但是当人们用“你为什么要这样做?”回答问题时我讨厌它。正如已经指出你的 longjmp()用法是错误的。这是一个如何正确使用它的简单示例:

#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;
}

使用longjmp()的问题如下:

  1. 您不会调用setjmp()
  2. 您尚未在堆栈上或动态分配jmp_buf。 jmp_buf * bfj 只是一个指针。
  3. 您无法将 char * 强制转换为 jmp_buf * 并期望它能够正常运行。 C ++不是静态编译的动态语言。
  4. 但实际上,您根本不可能使用 longjmp()

答案 2 :(得分:2)

你完全失败的C ++。首先,goto是坏的,而不是没有经验的 - 有一个原因,因为,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!");
}

答案 3 :(得分:0)

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


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

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


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

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

答案 4 :(得分:0)

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

尽管setjmp()/ longjmp()有时适用于纯C程序,但让C程序调用setjmp()来创建快照,然后调用一些C ++代码,然后调用longjmp()返回到该快照,是灾难的秘诀。几乎所有人都希望这样做的情况可以通过例外来更好地处理。