是否有某些版本的 longjmp 可以输出 long 值?

Is there some version of longjmp that can output long values?

我正在开发一个 C 语言的框架,为此我想实现异常,为此我使用带有 setjump 的 longjump,但在 x64 机器上 longjump 仍然输出一个整数。

我创建了一个 class(本质上是带有 vptr 的结构),它表示异常,但要在代码中将其抛出,我需要抛出一个指向该结构的指针。对于 x64 机器,指针有一个 unsigned long long 值(qword),对于 x86,指针有一个 unsigned int(dword),所以我只需要 qword在输出中处理错误。

longjmpsetjmp的实现可以输出qword吗?

或者我可以自己编写 longjump,但需要原始源代码。

如果你想便携,那么你可以使用数组索引,存储所有 64 位指针的数组(或者只是一个指向结构的指针数组,其中包含关于在某些异常情况下要做什么的信息页面) .

如何填充这样的数组是另一个问题。当然,你不需要用所有可能成为异常的实例来填充数组,只需要用 try-ed 并且能够 catch 的那些。但可能你需要的不仅仅是一个指针(因为你必须处理运行时情况,在这种情况下你有相同的异常,在堆栈中的多个 active 位置被捕获。)

一旦你解决了上面的问题,也许你甚至可以使用 short int 来解决这个问题,一旦你理解了你需要解决的问题的本质。

根据阅读评论,我看到您评论说由于多线程问题,全局变量不合适。首先,你可以在线程的上下文中让它全局(例如errno变量),因为这就是使用void *调用的原因线程执行的例程,returns 完成后返回。你可以在那里拥有它,专用于线程全局数据。

第二点,如果你想从 C 的角度管理这些奇怪的事情,比如以奇怪的方式操纵堆栈,提到的函数可以(我不相信你完全了解内部结构setjmp()/longjmp() 的工作。)我可以告诉你 setjmp()/longjmp() api 是很久以前写的(在 50 的范围内years now), 在旧的 V6 unix 代码时代,为了应对未知的 unix 设备驱动程序错误处理 --- 一个非常受控和简单的环境 ---) 简单地说, longjmp() 的使用要复杂得多(并且强烈劝阻,即使是他们的作者 K & R)而不是切换到完全支持其核心异常的不同语言(如建议的 C++)(这个建议不是我的,它已经在你的问题的评论中建议)

第三。如果你使用 setjmp()longjmp() 你还需要知道它们(两者)使用调用线程的堆栈来标记指针和 去哪里 来存储信息。因此,您必须控制,例如,如果您在信号处理程序中执行 longjmp(),则可能会严重破坏执行信号处理程序的线程堆栈(即被信号中断的线程)如果它与执行 setjmp() 调用的线程不同。这样做的原因是被中断的线程将与执行 setjmp() 的线程之一切换其堆栈,并且两个线程将在不同点开始使用相同堆栈执行代码,这将跳回到执行时间这两个功能(当时只有一台 pdp 计算机可用,没有今天常见的多个 cpus/cores,所以 只有一个堆栈 )这里要特别小心,因为通常情况下,生成异常的线程与 捕获 它的线程相同,但是对于异步陷阱,这可能是错误的,比如信号处理。

顺便说一下,你做的事情很有趣,会让你知道一种语言是如何实现内部复杂行为的,比如异常处理。我为你尝试这种事情的勇气鼓掌,不要犹豫,如果你需要 C++ 方面的导师,我会为你提供帮助。

不要放弃!!

您可以将 jmp_buf 类型的变量包含在更大的结构中,可能只大 sizeof(void*)。然后就在调用 longjmp() 之前,您可以将指针存储在那个额外的 space 中。无需尝试将指针压缩为 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;
}

Output:

Threw 0x55638ebc78c4 = "Exception message!".