QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 923|回复: 9

各位大侠,好久不见了!

[复制链接]
发表于 2005-7-20 14:19:28 | 显示全部楼层 |阅读模式
大家好,好久没有过来这边了呢,呵呵!真的好怀念!
小妹在这里,有个问题想请教各位大侠,在linux有用过longjmp();和setjmp();吗?谁可以告诉我,为什么我设置了一个setjmp之后,当程序运行到longjmp,跳转到setjmp,运行了一个printf之后,程序全部跳出,终端显示显示断错误呢?
void tppaintForm::aaa
{  
  ................
  
  setjmp(buf);

printf("close paint is %d\n",paintclose);


printf("asdfghhhhh\n");

}

void tppaintForm::bbb()
{
  paintclose=1;
  printf("paint endend\n");
  longjmp(buf,0);   
}

在终端可以看到
close paint is 1

asdfghhhhh
段错误

之后就跳出了,555555555
各位大侠,请指点,我到底错哪里了呀?万分感谢!!!
发表于 2005-7-20 14:32:09 | 显示全部楼层
C++里不要使用setjmp和longjmp,应该用exception。

而且,setjmp一定要用在调用方,longjump用在被调用方,
而不能用在平行的两个函数里,否则没有正确的栈内存数据。
回复

使用道具 举报

 楼主| 发表于 2005-7-20 15:26:44 | 显示全部楼层
这样呀,可是,setjmp不就是在需要的时候设置调用吗?为什么要用在被调用方呢???是不是说这2个函数要有调用和被调用的关系呢???

可是exception怎么用呢?我不会呀!55555555555

我想要实现的就是当运行void tppaintForm::bbb()函数时,可是,跳回到void tppaintForm::aaa的 setjmp(buf);设置的地方做一些事,该怎么做呢?
回复

使用道具 举报

发表于 2005-7-20 15:44:47 | 显示全部楼层
setjmp和longjmp的意思是处理某些难以恢复的错误,
跳回到调用上层,说穿了就是异常处理。

你的情况干脆调用aaa不就行了,或者把那部分代码
单抽成一个函数,为什么要用xxxjmp这些需要使用
者清楚的明白系统内部原理的危险方法呢?
回复

使用道具 举报

 楼主| 发表于 2005-7-20 19:33:17 | 显示全部楼层
那try catch? 可以用吗?如果可以,该怎么用呢?请指教,麻烦了*^_^*
回复

使用道具 举报

发表于 2005-7-21 05:36:10 | 显示全部楼层
[quote:53bfbc23e0="zt_apple"]那try catch? 可以用吗?如果可以,该怎么用呢?请指教,麻烦了*^_^*[/quote]
找本c++的书 看异常处理那一章节
回复

使用道具 举报

发表于 2005-7-21 16:40:13 | 显示全部楼层
最近比较忙!对这个问题最简单的解决方法就是到网上找一下有没有前辈对同样的问题作出解答:
在这里我转载一下别人写的东东:
[code:1]
         “setjmp和longjmp并不能很好地支持C++中面向对象的语义。因此在C++程序中,请使用C++提供的异常处理机制”。它在MSDN中的原文如下:
  setjmp and longjmp do not support C++ object semantics. In C++ programs, use the C++ exception-handling mechanism.

  这究竟是为什么?大家知道,C++语言中是基本兼容C语言中的语义的。但是为什么,在C++程序中,唯独却不能使用C语言中的异常处理机制?虽然大家都知道,在C++程序中,实际上是没有必要这么做,因为C++语言中提供了更完善的异常处理模型。但是,在许多种特殊情况下,C++语言来开发的应用程序系统中,可能采用了C语言中的异常处理机制。例如说,一个应用程序由于采用C++开发,它里面使用了C++提供的异常处理机制;但是它可能需要调用其它已经由C语言实现的程序库,而恰恰在这个被复用的程序库中,它也采用了异常处理机制。因此对于整个应用程序系统而言,它不可避免地出现了这种矛盾的局面。并且这种情况是非常多见的,也可能是非常危险的。因为毕竟,“setjmp and longjmp do not support C++ object semantics”。所以,我们非常有必要来了解它究竟为什么不会兼容。

  在本篇文章中,主人公阿愚将和程序员朋友们一起,深入探讨setjmp与longjmp机制,为什么它很难与C++和睦相处?另外还有,如果C++语言来开发的应用程序系统中,不得不同时使用这两种异常处理模型时,又如何来尽可能保证程序系统的安全?

C++语言中使用setjmp与longjmp

  闲话少说,还是看例程先吧!代码如下:

// 注意,这是一个C++程序。文件扩展名应该为.cpp或其它等。例如,c++setjmp.cpp
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>

//定义一个测试类
class MyTest
{
public:
MyTest ()
{
printf("构造一个MyTest类型的对象\n");
}

virtual ~ MyTest ()
{
printf("析构销毁一个MyTest类型的对象\n");
}
};

jmp_buf mark;

void test1()
{
// 注意,这里抛出异常
longjmp(mark, 1);
}

void test()
{
test1();
}

void main( void )
{
int jmpret;

// 设置好异常出现时,程序的回溯点
jmpret = setjmp( mark );
if( jmpret == 0 )
{
// 建立一个对像
MyTest myobj;

test();
}
else
{
printf("捕获到一个异常\n");
}
}

  请编译运行一下,程序的运行结果如下:
  构造一个MyTest类型的对象
  析构销毁一个MyTest类型的对象
  捕获到一个异常

  上面的程序运行结果,那么到底是不是合理的呢?阿愚感到有些纳闷,这结果肯定是合乎情理的呀!从这个例程来看,setjmp和longjmp并不能破坏C++中面向对象的语义,它们之间融洽得很好呀!那么为什么会说,“setjmp and longjmp do not support C++ object semantics”。请不要着急,沉住气!继续看看其它的情况,代码如下:

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

class MyTest
{
public:
MyTest ()
{
printf("构造一个MyTest类型的对象\n");
}

virtual ~ MyTest ()
{
printf("析构销毁一个MyTest类型的对象\n");
}
};

jmp_buf mark;

void test1()
{
// 注意,这里在上面程序的基础上,进行了一点小小的改动
// 把对像的构造挪到这里来
MyTest myobj;

longjmp(mark, 1);
}

void test()
{
test1();
}

void main( void )
{
int jmpret;

jmpret = setjmp( mark );
if( jmpret == 0 )
{
test();
}
else
{
printf("捕获到一个异常\n");
}
}

  同样也编译运行一下,看程序的运行结果,如下:
  构造一个MyTest类型的对象
  捕获到一个异常

  呵呵!那个对像的构造建立过程只不过是被稍稍挪了一下位置,而且先后顺序还没有改变,都是在if( jmpret == 0 )语句之后,longjmp(mark, 1)之前。可为什么程序运行的结果却不同了呢?显然,从这个例程的运行结果来看,setjmp和longjmp已经破坏C++中面向对象的语义,因为那个MyTest类型的对像只被构造了,但是它却没有被析构销毁!这与大家所知道的面向对象的理论是相违背的。程序员朋友们,不要小看这个问题,有时这种错误将给应用程序系统带来极大的灾难(不仅仅是内存资源得不到释放,更糟糕的是可能引发系统死锁或程序崩溃)。

  由此可以看出,setjmp与longjmp机制,有时的确是不能够与C++和睦相处。那么,为什么第1个例子中会安然无恙呢?它有什么规律吗?请继续看另外的一个例子,代码如下:

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

class MyTest
{
public:
MyTest ()
{
printf("构造一个MyTest类型的对象\n");
}

virtual ~ MyTest ()
{
printf("析构销毁一个MyTest类型的对象\n");
}
};

jmp_buf mark;

void test1()
{
longjmp(mark, 1);
}

void test()
{
/ // 注意,现在又把它挪到了这里
MyTest myobj;

test1();
}

void main( void )
{
int jmpret;

jmpret = setjmp( mark );
if( jmpret == 0 )
{
test();
}
else
{
printf("捕获到一个异常\n");
}
}

  请编译运行一下,程序的运行结果如下:
  构造一个MyTest类型的对象
  析构销毁一个MyTest类型的对象
  捕获到一个异常

  呵呵!这里的运行结果也是对的。所以主人公阿愚总结出了一条结论,那就是,“在longjmp被调用执行的那个函数作用域中,绝对不能够存在局部变量形式的对象(也即在堆栈中的对象,longjmp执行时还没有被析构销毁),否则这些对象将得不到析构的机会”。切忌切忌!又例如下面的例子同样也会有问题,代码如下:

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

class MyTest
{
public:
MyTest ()
{
printf("构造一个MyTest类型的对象\n");
}

virtual ~ MyTest ()
{
printf("析构销毁一个MyTest类型的对象\n");
}
};

jmp_buf mark;

void main( void )
{
int jmpret;

jmpret = setjmp( mark );
if( jmpret == 0 )
{
MyTest myobj;
longjmp(mark, 1);
}
else
{
printf("捕获到一个异常\n");
}
}

总结

   虽然说,setjmp与longjmp机制,很难与C++和睦相处。但是它并非那么可怕,只要掌握了它的规律,整个应用程序系统的安全性仍掌握在你手心。而且,本文开头提到的例子(采用C++开发的应用程序,它里面调用了C语言实现的其它程序库,并且库代码中使用了setjmp和longjmp机制),它并没有任何的问题。因为这个C库中,其中调用longjmp的函数域内,决不会有对象的构造定义。

  现在为止,对setjmp和longjmp的讨论暂告一个段落。在“爱的秘密”篇中,会进一步阐述它的实现。下一篇文章将讨论在C++中,如何兼容并支持C语言中提供的其它方式的异常处理机制(例如,C++中对goto语句的支持)。哈哈! goto next!

[/code:1]
回复

使用道具 举报

 楼主| 发表于 2005-7-22 21:06:14 | 显示全部楼层
我发现了一个问题,如果是我普通的一个slot();用longjmp & setjmp是完全没有问题的(已经实践过了),只有在void Form::paintEvent(QPaintEvent *)里,不可以用,为什么会这样??????难道这个QT默认的函数和我声明的其他自定义的slot,有什么不一样的地方吗?请教大侠们!!!!!!!!拜托了~>_<~
回复

使用道具 举报

发表于 2005-7-22 22:52:26 | 显示全部楼层
简单的说一下为什么不能随便用setjmp和longjmp

栈是一种先进后出的内存结构。

c的函数调用是通过栈来进行的,找本计算机原理的
书,里面会讲解是如何通过栈保存正确的返回地址,
传递参数,以及通过栈来分配局部变量的。

简单的说,c语言的函数是依靠栈内存来保存函数返回
地址的,而栈里的东西是有顺序的,不能随便分配释放。
setjmp和longjmp会破坏正常的栈顺序,如果你不
按照严格的上下关系使用它们,栈里就会没有函数返回
时需要的指令地址,cpu就会因为没有正确的指令执行而
发出异常指示让操作系统杀掉你的程序。


到了c++里,这个问题更复杂了,因为c++会用
栈来处理局部对象,你更不能随便用setjmp和longjmp
来胡改栈里的内容了。

我想你一定知道局部对象在函数返回时会自动调用他们的
析构函数,但是如果使用longjmp就绝对不会调用析构函数,
这是非常危险的。

但是try catch就会,这是为什么c++的教科书里一再强调
用try catch代替xxxjmp的原因。
回复

使用道具 举报

发表于 2005-7-23 11:46:40 | 显示全部楼层
唉,我到现在还不明白堆、栈的实质。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-5 17:33 , Processed in 0.038066 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表