我必须将C用于一个项目,我正在考虑使用longjmp/setjmp错误处理,因为我认为在一个中心位置处理错误要比返回代码容易得多.如果有一些关于如何做到这一点的线索,我将不胜感激.
如果发生任何此类错误,我特别关注正确完成资源清理.
另外,我如何处理导致多线程程序使用它们的错误?
更好的是,是否有一些C库已经存在以进行错误/异常处理?
在调用longjmp()之后,如果自调用setjmp()以来它们的值可能已更改,则不应访问非易失性限定的本地对象.在这种情况下,它们的值被认为是不确定的,访问它们是未定义的行为.
现在我的问题是为什么在这种情况下挥发性工作?不会改变那个volatile变量仍然无法使用longjmp吗?例如,longjmp在下面给出的示例中将如何正常工作?当代码在longjmp之后返回setjmp时,local_var的值不是2而不是1吗?
void some_function()
{
volatile int local_var = 1;
setjmp( buf );
local_var = 2;
longjmp( buf, 1 );
}
Run Code Online (Sandbox Code Playgroud) 我编写了一个测试来测量带有线程的C++异常的成本.
#include <cstdlib>
#include <iostream>
#include <vector>
#include <thread>
static const int N = 100000;
static void doSomething(int& n)
{
--n;
throw 1;
}
static void throwManyManyTimes()
{
int n = N;
while (n)
{
try
{
doSomething(n);
}
catch (int n)
{
switch (n)
{
case 1:
continue;
default:
std::cout << "error" << std::endl;
std::exit(EXIT_FAILURE);
}
}
}
}
int main(void)
{
int nCPUs = std::thread::hardware_concurrency();
std::vector<std::thread> threads(nCPUs);
for (int i = 0; i < nCPUs; ++i)
{
threads[i] …Run Code Online (Sandbox Code Playgroud) 我通常不会编写C++代码,但我的一个奇怪的comp sci朋友厌倦了查看我精彩的FORTRAN程序并挑战我用C++重写其中一个,因为他更喜欢我的C++代码.(我们在这里投入资金.)确切的术语是它需要在现代C++编译器中进行编译.也许他讨厌一个好的conio.h - 我不知道.
现在我意识到在C++中有很好的写作方式,但是我想通过尽可能使我的C++版本成为FORTRAN-esque来获得个人胜利.对于奖励积分,当我转换代码时,这可能会节省一些时间和精力.
所以!这带我进入以下相关查询:
在gotos:
在longjmp上:
现在我的主要关注点是为此计算goto.看起来我可能会使用longjmp来完成这项工作,因为void指针数组不是C++标准的一部分,而是GCC特定的扩展.
我正在调查setjmp/longjmp,发现setjmp保存了诸如指令指针,堆栈指针等寄存器......
但是我不知道的是,在调用setjmp和longjmp之间,不能修改线程堆栈中的数据本身.在这种情况下,不会longjmp不能按预期工作.
为了说清楚,例如,当longjmp恢复堆栈指针时,说现在堆栈指针所指向的内存中的数据与调用setjmp时的数据不同.这会发生吗?如果发生这种情况,我们不是有麻烦吗?
另外,语句的意思是" 在调用setjmp()例程的例程返回后,可能不会调用longjmp()例程. "
我已经读过传入的jmp_buf变量中的setjmp"保存程序状态",但是我还没有找到任何关于它究竟是什么的描述.它是否复制了所有应用程序的内存?只是寄存器?堆栈?
我正在编写多平台代码,需要使用指向setjmp/sigsetjmp的指针.通常情况就是如此简单
#include <setjmp.h>
void * sigsetjmp_p = sigsetjmp;
Run Code Online (Sandbox Code Playgroud)
但是,ISO和POSIX声明setjmp/sigsetjmp可以定义为宏,事实上我的linux框就是这种情况.以下摘录自/usr/include/setjmp.h:
# define sigsetjmp(env, savemask) __sigsetjmp (env, savemask)
Run Code Online (Sandbox Code Playgroud)
问题是,由于我没有传递参数sigsetjmp,宏不会扩展,并且sigsetjmp在libc中没有定义普通符号.我希望能够使用一些宏"黑魔法"来提取"__sigsetjmp"名称,但到目前为止我已经失败了.
另一种选择是__sigsetjmp直接使用 ,但这意味着检查每个支持平台的扩展,我不想这样做(因此这个问题的原因).
PS:我讨厌宏.
注意:
我需要它的原因有点模糊,但为了简化它,我想说我想用它进行指针比较.
#include <setjmp.h>
int equals_sigsetjmp(void *p)
{
void * sigsetjmp_p = sigsetjmp;
return p == sigsetjmp_p;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
是的是的.我知道我不应该指望指向sigsetjmp它,因为它甚至可能不是某些平台上的函数,但这并不能解决我的问题.
在实践中,我所知道的所有平台都将其作为一个功能实现.
我可以应对这样一个事实:在几年内,我遇到了一个sigsetjump不适合某个平台的案例.但我不想应对的是通过每个支持的平台并检查setjmp.h宏定义,这是我现在唯一的选择.
我很欣赏标准的参考,但我希望得到一个实际的答案而不是纯粹的答案.
在该手册页longjmp和setjmp,有这样一行:
如果调用
setjmp()之前longjmp()调用的函数被调用,则行为未定义.
这是否意味着我实际上必须在调用longjmp的函数setjmp或嵌套函数中的某个地方调用?或者根本不打电话可以吗?
我知道setjmp和longjmp的定义.setjmp将环境存储在堆栈上下文中,另一个恢复.
但我认为我的某些方面缺乏某种理解.有人可以借助好的例子来解释我,我如何保证,如何保存以及如何恢复它?
我看到jmp_buf中有很多CPU寄存器.但我怎么保证它恢复了?
请帮我用简洁的例子来解释.我用谷歌搜索并提到堆栈溢出的其他问题,但没有一个给出明确的例子.
非常感谢提前.
PS:它应该仅来自Linux/Unix上下文.
我大多说服自己,我遇到了一些g ++ 4.8.3错误,但我想我会首先问这个列表,因为我对setjmp/longjmp的经验很少.我将我的代码简化为以下foo.cxx:
#include <setjmp.h>
#include <string.h>
// Changing MyStruct to be just a single int makes the compiler happy.
struct MyStruct
{
int a;
int b;
};
// Setting MyType to int makes the compiler happy.
#ifdef USE_STRUCT
typedef MyStruct MyType;
#elif USE_INT
typedef int MyType;
#endif
void SomeFunc(MyType val)
{
}
static void static_func(MyType val)
{
SomeFunc(val);
}
int main(int argc, char **argv)
{
jmp_buf env;
if (setjmp(env))
{
return 1;
}
MyType val;
#ifdef USE_STRUCT
val.a = …Run Code Online (Sandbox Code Playgroud)