论坛首页 编程语言技术论坛

异常处理写法 和 windows x86 向x64移植 的问题

浏览 9586 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-11-12   最后修改:2010-11-25
C++
回复已解决我的疑问了,
请问怎么把这贴子转去问答区或是入门讨论?

以前的贴子自己理解有误,觉得没啥可问的,就删除重写了,新手要个"前车之鉴"的,就看一下1,8楼好了.

不讨论"用try-catch处理异常好,还是用error code好"
只是问怎么在C++中用好try-catch

现在大部分的C++异常处理都是用error code判断返回值
比如下面的代码,就是我在公司看到的,还有更多的GOTO的就不举例了.

ERROR SomeFunc3()
{
    //...
    do
    {
        // ...
        eRet = DoSomeThing1();
        if (ERR_NONE != eRet)
        {
           break;
        }
        
        eRet = DoSomeThing2();
        if (ERR_NONE != eRet)
        {
           break;
        }

        // more code like above

    }while(false)
   
    // release memory, handle or something.
    return eRet;
}


如果用JAVA代码,我可能会这样写



MyBaseException extends RuntimeException
MyException1 和 MyException2 extends MyBaseException

class Moudle {
  public void DoSomeThing1() {
    // ...

    // 假设连接主机失败
    if (expect != value) {
      throw new MyException1("error context" + value);// 是个 runtime exception  
    }

    // ...

    // 假设版本不对
    if (expect2 != value2) {
      throw new MyException2("error context"  + value2);// runtime exception
    }

    // ...
  }

  public void DoSomeThing2() {

    // ...

    // 假设连接主机超时
    if (expect3 != value3) {
      throw new MyException1("error context"  + value3);// runtime exception
    }

    // ...

    // 假设外部DLL有错
    if (expect4 != value4) {
      throw new MyException2("error context"  + value4);// runtime exception
    }

    // ...
  }
}

//另一个CLASS的方法中
class APILike {
  public void SomeFun3() {
    Moudle mm = new Moudle ();
    try {
       mm.DoSomeThing1();
       mm.DoSomeThing2();
       // ...
    } catch (MyException1 e) {
       // handle exception 或是不catch这个异常
    } catch (MyException2 e) {
       // handle exception 或是不catch这个异常
    } catch (MyBaseException e) {
       // 把错误发给用户
       SendInfoToUI(e.getMessage());
    }
    // ...
  }
}


JAVA代码很好理解,异常也很好扩展.


只针对以上JAVA代码,如果在C++中用try-catch要怎么做(能给伪代码吗)?异常体系如何定义?参考了一下MSDN,里面还有__try(好象WINDOWS专用?),更把我搞糊涂了.


============================================================================

问题2:

有一个32位程序要移植到64位上,我在 WIN XP & VS2005 & 活动解决方案平台x64 上编译出EXE和DLL,COPY到一台WIN2003 x64 的 F:\Program Files (x86)\XXXXXX 下运行. works just fine.

然后我在x64机器上用depends工具(64位版)view了一下DLL,在面版里发现我自己的DLL,cpu显示为x64 ,但是它depend的系统DLL,比如说KERNEL32.DLL是在windows\syswow64下的那个(不明白为啥不是system32下),WINMM.DLL是windows\system32下的, 所有系统DLL CPU显示均为X86.

我知道syswow64是windows-on-windows 64的意思, 里面放的DLL用来兼容32位程序.而system32里是放64位版本的DLL.

然后用depends工具(64位版)view了一下windows\system32\kernel32.dll发现cpu显示为x86...好象所有的系统DLLCPU都是显示x86,难道不应该是x64吗?

我在WINXP(x86)上编译时,link的系统DLL的导入库(比如说winmm.lib wininet.lib)应该都是32位的吧

PS:不讨论"最好最省事的方法是在x64系统的x86 32位虚拟机里面运行32位程序,避免移植到x64的工作量和风险。 "因为还要移植LINUX64.

以前没有做过X86 TO X64, 如果在WIN x64上直接跑32位的程序,会影响性能吗?比如说,字长需要转换的什么





   发表时间:2010-11-12  
zx339 写道
Hi all,
  很担心我正把一个应该归类于"入门讨论"的话题(问题)post在C++区,进一步恶化了"C++区无营养",导致有经验C++ dev更加远离不活跃的C++区.PS:我有2年的C++的工作经验.

问题发现在维护别人代码上.只考滤 windows, VS IDE, 非嵌入式(内存足), 支持多线程 的情况下.
1,const修饰函数内变量.
ERRCODE SomeFunc(HANDLE* pHandle)
{
   // ...
   const char * pStep = pHandle->szStep;
   // ...
}

我可以理解,原作者的意思是防止在接下来的代码里,因为改变pStep而改变了pHandle->szStep,所以给pStep加上了const.
(后来又考滤了一下,加了 const 也没用,除非是用char const * pStep)
很简单,可以马上觉得用const修饰函数参数是才比较正确的方法.
此时的pStep指针,应该是在分配常量区的指针吧?应该不会跟随函数栈被收回?
以此推出const修饰函数内变量无意义. 成立吗?

2,函数内定义结构体
ERRCODE SomeFunc2(void *SomePoint)
{
   struct Config
   {
       char * a;
       void * b;
       int    c;
   }
   Config cfgDefault[] = {
       {"aaaa", SomePoint->member1, 11},
       // ... something like above.
   };

   // ... some code use cfgDefault
}

把结构体定义在函数内会影响效率吗?把结构体定义放在外面的话和现在比,有啥不同?个人觉得写在函数内或外编译后的效果可能是一样的,只是单纯的觉得这样的代码很geek,还是我少见多怪了?

3,异常处理流程
虽然各种教科书都说 goto很evil,但是实际工作中,看到goto身影的机会还是很多.
也许出于历史原因, 版本原因, 程序运行环境原因, <script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/themes/advanced/langs/zh.js"></script><script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/plugins/javaeye/langs/zh.js"></script>只能用返回值和GOTO来控制异常处理流程.

以下流程我是真是第一次见识.

ERROR SomeFunc3()
{
    //...
    do
    {
        // ...
        eRet = DoSomeThing1();
        if (ERR_NONE != eRet)
        {
           break;
        }
        
        eRet = DoSomeThing2();
        if (ERR_NONE != eRet)
        {
           break;
        }

        // more code like above

    }while(false)
   
    // release memory, handle or something.
    return eRet;
}


用try-catch-throw会影响性能,因为要压栈什么的.情问这种影响大吗?可移植性呢?
工作这几年也基本上没看到过用try-catch-throw来处理的,一些书上也只是写个简单用例,有好一点的资料吗?





2. 结构体在函数里是为了定义私有的结构体,仅供本函数使用吧,从阅读上也方便,不需要上下翻找。

3. Java是一定要处理异常,C#不需要强迫处理异常,所以要不要try catch取决于程序员。

design by contract里有个很有意思的话题,什么时候是异常,什么时候是错误。
0 请登录后投票
   发表时间:2010-11-20   最后修改:2010-11-20
1.关于const,char const * pStep 和 const char * pStep是一回事,在你的函数里,想表示szStep指向一个不可改变的内存。作者这么写有两个原因,不写const,你编译不过,因为pHandle->szStep返回的是const,没有类型转换,编译不过(希望你的是正常的编译器和警告等级);第二,想防止对指向内存作修改。

2.函数体内定义局部结构体或类,只是表示该类的作用域在函数内,相当于函数的一个助手,放在外边,扩大了作用域,区别明显吧?

3.try-catch-throw之类的性能不用考虑,估计影响不大。但在c++大型项目中,和JAVA不一样,c++由于返回值(多值输出),全局变量的存在,状态的表示即使在跨层下,也不一定非得用异常,也许基于网络的应用会定义一套异常继承结构(我没做过,PS异常体系不好定义),异常的加入还会使多人的并发开发项目变得不容易调试,所以总体上用异常来控制主要的出错逻辑的c++大型项目很少(我没见过)。

PS:可能对于逻辑集中的库中利用异常来控制的还是有的,但对于集合了各种逻辑的应用程序来说,异常来控制真的是很不好控制。
0 请登录后投票
   发表时间:2010-11-20  
GOTO正确使用,用到的也就3个作用
1.出错前打印一下出错信息;
2.表示某个变量值改变后,再重新做一遍操作,一般就是和Label again, retry连用,因为这样比循环可以更好的表示代码意图。
3.跳出多重循环。
你给的例子哪有GOTO?
0 请登录后投票
   发表时间:2010-11-20   最后修改:2010-11-20
贴段代码(摘自netbsdsrc/lib/libc/net/getservent.c:65–104)


again:
    if ((p = fgets(line, BUFSIZ, servf)) == NULL)   
        return (NULL);

    if (*p == '#')   
        goto again;
    cp = strpbrk(p, "#\n");
    if (cp == NULL)   
        goto again;
    *cp = '\0';   
    [...]
    return (&serv);
0 请登录后投票
   发表时间:2010-11-21  
zx339 写道
Hi all,


用try-catch-throw会影响性能,因为要压栈什么的.情问这种影响大吗?可移植性呢?
工作这几年也基本上没看到过用try-catch-throw来处理的,一些书上也只是写个简单用例,有好一点的资料吗?






好的编译器会尽可能消减这个开销的,不过好像ACE里面放弃了C++异常是因为他搞不清构造函数的行为?

一般如果你知道你的代码有 /0的bug, 那么这个时候用个异常让程序正常跑还是不错的,只要不用于逻辑。

最好的情况就是,用了异常但是没有执行的效率和没用一样。
0 请登录后投票
   发表时间:2010-11-21  
1.const char * pStep和char const * pStep一模一样的,与char*const pStep是不一样的。
2.函数内部类的使用场合是一些类只在一个函数内有用,在函数外无意义。类型应该尽量定义的可见范围更小,好处是修改的时候代价更小。
3.说实话建议不要使用C++的异常机制,尤其在大项目里面。C++可以有多值返回,所以不要将异常当作带额外返回值的手段。
话说你这两年C++基础不是很扎实啊,尤其是第一个问题。
标准C++的类型修饰符是放在类型右侧的,但是为了兼容例如const也可以放在左边。
举个例子:
char   -> 基础类型
char const -> const 修饰了char,代表不可变的char
char const *  -> *修饰了char const,代表指向了一个不可变的char const的指针,但是这个指针本身可变。
char const * const -> const 修饰了 char const *,代表这个指针本身也不可变。
char * -> *修饰了char,代表指向了一个可变的char的指针
char* const-> const 修饰了char*,代表了指向一个可变char的不可变指针。

char const是标准写法
const char是兼容写法,与char const等效,不过目前倒是这个比较常见。

其实能正确的使用const,可以很好的体现一个C++程序员的素质。
0 请登录后投票
   发表时间:2010-11-22  
// a is a pointer to int const;
const int *a;

// a is a const pointer to int;
int *const a = &n;

// a is a const pointer to int const;
const int *const a = &n;

0 请登录后投票
   发表时间:2010-11-24   最后修改:2010-11-25
thinkx 写道
1.const char * pStep和char const * pStep一模一样的,与char*const pStep是不一样的。
2.函数内部类的使用场合是一些类只在一个函数内有用,在函数外无意义。类型应该尽量定义的可见范围更小,好处是修改的时候代价更小。
3.说实话建议不要使用C++的异常机制,尤其在大项目里面。C++可以有多值返回,所以不要将异常当作带额外返回值的手段。
话说你这两年C++基础不是很扎实啊,尤其是第一个问题。
标准C++的类型修饰符是放在类型右侧的,但是为了兼容例如const也可以放在左边。
举个例子:
char   -> 基础类型
char const -> const 修饰了char,代表不可变的char
char const *  -> *修饰了char const,代表指向了一个不可变的char const的指针,但是这个指针本身可变。
char const * const -> const 修饰了 char const *,代表这个指针本身也不可变。
char * -> *修饰了char,代表指向了一个可变的char的指针
char* const-> const 修饰了char*,代表了指向一个可变char的不可变指针。

char const是标准写法
const char是兼容写法,与char const等效,不过目前倒是这个比较常见。

其实能正确的使用const,可以很好的体现一个C++程序员的素质。


thanks for reply.
事情是这样的,当时看别人一个函数的源代码开头有以下两句:
const int n = pHandle->unSize;
const char * pStep = pHandle->szStep;
// some code use n and pStep

函数原型大概是这样:
void SomeFun(HANDLD * pHandle);

我当时觉得加const 来修饰没啥用, 整型是直接赋值了,没用;const char* 的话,参数const HANDLD* pHandle就行了.
函数里面用const不好,所以贴出来问一下.
char const * 和 const char *是一回事这点我搞忘了,这个丢人了. 看代码时把const char * p当时理解成 char * const p了, 因为后者可以 p[2] = 'a';而改变内容.
所以当时觉得const修饰函数内变量无意义.

然后又看到一段代码,一个函数内部定义了类,我当时想,嵌套类不就好了么,非写在函数里干嘛?所以又拿出来问了一下.

现在觉得自己有点偏执,有点一根经, const Iterator自己也用得不少, 函数内部定义的类,编译器也会优化,
所以贴子1,2两点的讨论完全没啥意义,我就删除掉了,只问一下C++中的异常写法和我新加的一个64位迁移的问题.

0 请登录后投票
   发表时间:2010-11-25   最后修改:2010-11-25
1.char * const 和 const char *不是一回事。const出现在*的左边是一回事,const出现在*的右边是一回事。

2.c++中加异常和JAVA加异常语法是差不多的,你可以选择继承std下的exception, bad_cast, runtime_error, logic_error, bad_alloc等类。不过c++异常要比java异常考虑的东西要多,你得将自己定义的异常定义virtual虚构函数,你得将异常所在函数前面将堆上的资源或其他资源自己释放,所以你必须得考虑用智能指针改写前面的代码,另外,如果是非runtime_error的异常,你将改变函数的签名,c++中由于函数指针的存在,宏等其他一些用法,并且你的项目恰好用到了这些,你添加异常到函数接口带来的可能出错的机会是很大的。

3.x86转换到64位,其实就是windonws将中间添加了一个转换层,这个转换层截取一些函数调用,并将其恰当的粘合到win64上,但是这个转换层是工作在用户态的,所以如果你写驱动程序(内核),那你就得重写了(这个不介绍,很多内容)。估计你不是写驱动程序的,所以你只要测试一下在64下的程序即可。另外,你不要考虑性能,添加转换层将你的类型转换为64位类型,是必然需要性能损耗的,相信你也不是写性能敏感的程序的,如果性能无法接受,再考虑重写。

0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics