вопрос с longjmp - PullRequest
       4

вопрос с longjmp

1 голос
/ 21 июня 2010

Я хочу использовать longjmp для имитации инструкции goto. У меня есть массив 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>' к типу __jmp_buf_tag (*)[1]

Ответы [ 5 ]

5 голосов
/ 22 июня 2010

Вы, вероятно, вообще не хотите использовать 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 ++ не динамический язык, он статически компилируется.

Но на самом деле очень маловероятно, что вам вообще следует использовать longjmp () .

5 голосов
/ 21 июня 2010

Нормальным способом использования longjump является использование команды setjump (), как описано здесь .Кажется, вы хотите создать перемычку, как это обычно делается с помощью switch-case или виртуальных функций.

В любом случае, метки в коде (время компиляции) недоступны для строк (время выполнения), так чтоуже ваша первая проблема.Вам действительно нужно узнать адрес, к которому вы хотите перейти, и я бы лучше всего поставил setjump () там, где находятся ваши ярлыки.

2 голосов
/ 21 июня 2010

Вы полностью потерпели неудачу в C ++.Во-первых, goto - это плохо, и не для непосвященных - есть причина, по которой, пока, перерыв, продолжение и т.д. существуют.Во-вторых, вы пытаетесь преобразовать строку в идентификатор, что невозможно во время выполнения, если вы не кодируете ее самостоятельно.В-третьих, вы .. пытаетесь привести 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!");
}
0 голосов
/ 22 июня 2010

Когда вызывается setjmp (), система эффективно делает снимок стека вызовов и параметров. Этот снимок будет действовать до тех пор, пока пользовательский код не выйдет из блока, в котором была вызвана setjmp (); если longjmp () вызывается с этим снимком, выполнение возобновится, как если бы setjmp () возвращался в первый раз, за ​​исключением того, что вместо возврата нуля он вернет второй параметр, переданный longjmp (). Очень важно отметить, что вызов longjmp () с недопустимым снимком может иметь очень плохие последствия. В некоторых системах такой недопустимый вызов может «работать», но может повредить систему таким образом, чтобы он впоследствии вышел из строя.

Хотя setjmp () / longjmp () иногда подходят для чистых программ на C, с помощью вызова программы setjmp () для C для создания снимка, а затем вызова некоторого кода C ++, который, в свою очередь, вызывает longjmp () для возврата к этому снимку Рецепт катастрофы. Почти все ситуации, в которых вы захотите это сделать, могут быть лучше обработаны с использованием исключений.

0 голосов
/ 21 июня 2010

Похоже, вы хотите указатель на функцию:


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

Это обрабатывает DS [TOP] .int_value как адрес и переходит к нему. Если вы хотите перейти туда, где находится DS [TOP] .int_value, вы бы:


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

В любом случае, уродливый, уродливый код. Но он должен делать то, что вы хотите.

...