Есть ли версия longjmp, которая может выводить длинные значения? - PullRequest
0 голосов
/ 15 апреля 2019

Я работаю над фреймворком на языке C, для него я хочу реализовать исключения, для него я использую longjump с setjump, но на машинах x64 longjump по-прежнему выводит целое число.

Я создал класс (по существу, структура с vptr), который представляет исключение, но чтобы выбросить его в коде, мне нужно добавить указатель на эту структуру. Указатель имеет значение unsigned long long (qword) для машин x64 и unsigned int (dword) для x86, поэтому для обработки ошибки мне потребуется только qword.

Существуют ли реализации longjmp и setjmp, которые могут выводить qword?

Или, может быть, я мог бы написать свой собственный longjump, но для этого требуется оригинальный исходный код.

Ответы [ 2 ]

1 голос
/ 18 апреля 2019

Вы можете заключить вашу переменную типа jmp_buf в большую структуру, возможно, больше всего на sizeof(void*). Затем непосредственно перед вызовом longjmp() вы можете сохранить указатель в этом дополнительном пространстве. Нет необходимости пытаться втиснуть указатель в int.

Пример:

#include <stdio.h>
#include <setjmp.h>

struct jmp_buf_struct
{
  jmp_buf jb;
  void* exc_ptr;
};

void may_throw(jmp_buf jb)
{
  struct jmp_buf_struct* jbs_ptr = (struct jmp_buf_struct*)jb;
  jbs_ptr->exc_ptr = "Exception message!";
  longjmp(jb, 1);
}

int main()
{
  struct jmp_buf_struct jbs;
  if (setjmp(jbs.jb))
  {
    printf("Threw %p = \"%s\".", jbs.exc_ptr, (char*)jbs.exc_ptr);
  }
  else
  {
    may_throw(jbs.jb);
    puts("Didn't throw.");
  }
  return 0;
}

выход

Threw 0x55638ebc78c4 = "Сообщение об исключении!".

1 голос
/ 18 апреля 2019

Если вы хотите быть переносимым, то можете использовать индексы массива для массива, в котором хранятся все 64-битные указатели (или просто массив указателей на структуры со страницами информации о том, что делать с каким-то исключением).

Как вы заполняете такой массив - это другой вопрос. Конечно, вам не нужно заполнять массив всеми экземплярами, которые могут стать исключением, только теми, которые у вас try -ed и способны catch . Но, вероятно, вам понадобится больше, чем просто указатель (так как вам приходится иметь дело со случаем времени выполнения, когда у вас есть одно и то же исключение, пойманное в нескольких активных местах в вашем стеке.)

Как только вы решите вышеуказанную проблему, возможно, вы даже сможете использовать short int для этой вещи, как только вы поймете природу проблемы, которую вам нужно решить.

Основываясь на прочтении комментариев, я вижу, что вы заметили, что глобальная переменная не подходит из-за проблем с многопоточностью. Во-первых, вы можете иметь его global в контексте потока (как, например, переменная errno), поскольку это является причиной использования void * для вызова подпрограммы, выполняемой потоком, и возврата назад, когда закончил. Вы можете иметь это там, частный, чтобы нанизывать глобальные данные.

Во-вторых, если вы хотите управлять такими странными вещами с точки зрения C, как странные способы манипулирования стеком, упомянутые функции выполняют (я не думаю, что вы полностью знаете, как работают внутренние компоненты *). 1020 * / longjmp() работа.) Я могу вам сказать, что setjmp() / longjmp() API был написан давным-давно (в диапазоне 50 лет сейчас), во времена старого кода Unix V6, чтобы справиться с неизвестной обработкой ошибок драйверов устройств Unix - очень контролируемой и простой средой -) просто, использование longjmp() гораздо сложнее (и настоятельно не рекомендуется даже их авторами K & R), чем переключение на другой язык (например, C ++), который полностью поддерживает исключения в своей основе (эта рекомендация не моя, она была предложена в комментариях к вашему вопросу)

В-третьих. Если вы используете setjmp() и longjmp(), вам также необходимо знать, что они (оба) используют стек вызывающего потока для маркировки указателя и , куда идти для хранения информации. Таким образом, вы должны контролировать, например, что если вы сделаете longjmp() в обработчике сигнала, вы можете серьезно уничтожить стек потока, выполняющего обработчик сигнала (который был прерван сигналом), если он это не та же тема, что и тот, кто сделал вызов setjmp(). Причина этого заключается в том, что прерванный поток переключит свой стек вместе с потоком, который выполнил setjmp(), и оба потока начнут выполнять код с одним и тем же стеком в разных точках, что возвращает к времени реализации обоих функции (там был только компьютер pdp, без нескольких процессоров / ядер, как это принято сегодня, поэтому было только стек ). Здесь вы должны быть особенно осторожны, потому что обычно поток, который генерирует Исключением является то же, что места для ловят , но это может быть ложным для асинхронных ловушек, таких как обработка сигналов.

Кстати, то, что вы делаете, очень интересно, и позволит вам узнать, как язык реализует внутренне сложные поведения, такие как обработка исключений. Я аплодирую вам за вашу смелость пробовать подобные вещи, и не стесняйтесь, что если вам нужен наставник в C ++, я буду доступен для вас.

Только не сдавайся !!

...