谁能给我解释一下,在嵌入式编程中,setjmp()
和longjmp()
函数的具体用法是什么?我知道这些是用于错误处理的。但我想知道一些用例。
发布于 2013-02-04 19:42:15
其原理是,您可以将它们用于错误处理,这样您就可以跳出深度嵌套的调用链,而无需处理链中每个函数的错误。
就像每个聪明的理论一样,当遇到现实时,这一点就会崩溃。你的中间函数会分配内存,抓取锁,打开文件,做各种需要清理的事情。因此,在实践中,setjmp
/longjmp
通常不是一个好主意,除非在非常有限的情况下,您可以完全控制您的环境(一些嵌入式平台)。
根据我的经验,在大多数情况下,当您认为使用setjmp
/longjmp
可以工作时,您的程序足够清晰和简单,以至于调用链中的每个中间函数调用都可以进行错误处理,或者它是如此混乱和不可能修复,当您遇到错误时,您应该使用exit
。
发布于 2013-02-04 19:48:23
setjmp
和longjmp
的结合就是“超强goto
”。使用时要格外小心。然而,正如其他人所解释的那样,当您想要快速get me back to the beginning
时,longjmp
对于摆脱严重的错误情况非常有用,而不是必须为18层函数返回错误消息。
然而,就像goto
一样,但更糟糕的是,你必须非常小心地使用它。一个longjmp
会让你回到代码的开头。它不会影响在setjmp
和返回到setjmp
开始的位置之间可能发生更改的所有其他状态。因此,当您返回到调用setjmp
的地方时,分配、锁、半初始化的数据结构等仍然是分配的、锁定的和半初始化的。这意味着,你必须真正关心你做这件事的地方,在不引起更多问题的情况下调用longjmp
真的很好。当然,如果您下一步要做的事情是在存储有关错误的消息后“重新启动”,例如,在您发现硬件处于糟糕状态的嵌入式系统中,那么一切正常。
我还看到setjmp
/longjmp
被用来提供非常基本的线程机制。但这是非常特殊的情况--而且绝对不是“标准”线程的工作方式。
编辑:人们当然可以添加代码来“处理清理”,就像C++在编译后的代码中存储异常点,然后知道是什么引起了异常,什么是需要清理的。这将涉及到某种类型的函数指针表,并存储“如果我们从下面跳出来,用这个参数调用这个函数”。如下所示:
struct
{
void (*destructor)(void *ptr);
};
void LockForceUnlock(void *vlock)
{
LOCK* lock = vlock;
}
LOCK func_lock;
void func()
{
ref = add_destructor(LockForceUnlock, mylock);
Lock(func_lock)
...
func2(); // May call longjmp.
Unlock(func_lock);
remove_destructor(ref);
}
使用这个系统,你可以做“像C++一样完整的异常处理”。但它相当混乱,并且依赖于代码编写得很好。
发布于 2016-07-25 07:50:33
setjmp
和longjmp
在单元测试中非常有用。
假设我们想要测试以下模块:
#include <stdlib.h>
int my_div(int x, int y)
{
if (y==0) exit(2);
return x/y;
}
通常,如果要测试的函数调用另一个函数,则可以声明一个存根函数供其调用,该函数将模拟实际函数测试某些流的操作。但是,在这种情况下,该函数调用不返回的exit
。存根需要以某种方式模拟这种行为。setjmp
和longjmp
可以为您做到这一点。
为了测试这个功能,我们可以创建以下测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <setjmp.h>
// redefine assert to set a boolean flag
#ifdef assert
#undef assert
#endif
#define assert(x) (rslt = rslt && (x))
// the function to test
int my_div(int x, int y);
// main result return code used by redefined assert
static int rslt;
// variables controling stub functions
static int expected_code;
static int should_exit;
static jmp_buf jump_env;
// test suite main variables
static int done;
static int num_tests;
static int tests_passed;
// utility function
void TestStart(char *name)
{
num_tests++;
rslt = 1;
printf("-- Testing %s ... ",name);
}
// utility function
void TestEnd()
{
if (rslt) tests_passed++;
printf("%s\n", rslt ? "success" : "fail");
}
// stub function
void exit(int code)
{
if (!done)
{
assert(should_exit==1);
assert(expected_code==code);
longjmp(jump_env, 1);
}
else
{
_exit(code);
}
}
// test case
void test_normal()
{
int jmp_rval;
int r;
TestStart("test_normal");
should_exit = 0;
if (!(jmp_rval=setjmp(jump_env)))
{
r = my_div(12,3);
}
assert(jmp_rval==0);
assert(r==4);
TestEnd();
}
// test case
void test_div0()
{
int jmp_rval;
int r;
TestStart("test_div0");
should_exit = 1;
expected_code = 2;
if (!(jmp_rval=setjmp(jump_env)))
{
r = my_div(2,0);
}
assert(jmp_rval==1);
TestEnd();
}
int main()
{
num_tests = 0;
tests_passed = 0;
done = 0;
test_normal();
test_div0();
printf("Total tests passed: %d\n", tests_passed);
done = 1;
return !(tests_passed == num_tests);
}
在本例中,在输入要测试的函数之前使用setjmp
,然后在存根exit
中调用longjmp
直接返回到测试用例。
还要注意,重新定义的exit
有一个特殊的变量,它会检查您是否真的想要退出程序,并调用_exit
来执行此操作。如果您不这样做,您的测试程序可能不会干净地退出。
https://stackoverflow.com/questions/14685406
复制相似问题