工作中总结的编程小技巧2

技巧一:调试release程序的一个小方法

我们经常会发现调试release版本的程序时编译器有时无法提供正确的数值。那么可以将信息输出至测试文本或者调试窗口进行查看:

e.g:输出到文件

CRect rect;
m_cParamPanel.GetWindowRect(rect);
FILE * pfile = NULL;
pfile = fopen("test.txt","w");
fprintf(pfile,"create pos:%d,%d,%d,%d/n",rect.top,rect.left,rect.bottom,rect.right);
fclose(pfile);

 

技巧二:动态库设置别名的问题
让一个动态链接库文件debug和release编译的时候生成不同的文件名的方法:   
  1、去掉DEF文件中的LIBRARY;   
  2、修改settings-->link-->output file name,改为希望的名字,比如debug的改为test_d.dll,release的不变。  
  1很重要,否则虽然生成了test_d.dll和test_d.lib,但是运行的时候会报告找不到动态链接库"test.dll",因为test_d.lib中使用的internal name是"test.dll",去掉DEF文件中的LIBRARY以后就没有这个问题了!

 

技巧三:OpenGL编程过程中的错误信息输出

opengl不会自动将一些错误信息输出。需要显示调用glGetError函数并通过返回的错误码将错误字符输出。在发现渲染异常时调用下面的代码来查找opengl的error,有助于纠正潜在的错误。这些错误包括矩阵或者属性栈的溢出、非法操作等。下面的函数可先在绘制render函数的最开始进行一次调用,让错误信息清零。每绘制部分场景再调用一次,查看是否存在绘制错误。

void OpenglErrorOutput()

{

     GLenum errcode = glGetError();
     if (GL_NO_ERROR!=errcode)
     {
        const GLubyte * errstring = gluErrorString(errcode);
        char strerr[256];
        sprintf(strerr,"%s/n",errstring);
       OutputDebugStringA(strerr);
     }

}

 

技巧四:过多地在堆(STACK)上分配内存将产生以下错误
First-chance exception at 0x7c80bef7 in ParaTree.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0012e940..
Unhandled exception at 0x7c80bef7 in ParaTree.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0012e940..
建议如果需执行多次的操作需用动态new,或者采用异常检测机制。捕捉内存分配失败的异常。

 

技巧五:遍历删除vector中满足条件的元素

以前使用VC6开发,最近换用VS2005编译以前的程序,在运行时出现断言,切回调试器,发现提示是

"vector iterators incompatible”
引发这个错误的代码如下:

//====================旧代码

VectorType::iterator it = someVector.begin();
for (; it != someVector.end();)
{
     if (*it== value)
    {
         someVector.erase(it);
     }
     else
    {
         ++it;
    }
}

//====================

代码中,在erase操作后,没有修改it就继续循环,在与end()比较时,断言出现。

这里的主要问题是,vector可以用任意方法实现erase,不保证在erase一个元素后,后续的元素一定被移动到这个iterator所引用的位置(地址)。当然,这在几乎所有STL的实现中,都是对的,这也就是以前用VC6编译后运行没有问题的原因。但如果这里用的不是vector,而是list或是map,运行到这里,程序会毫不犹豫的崩溃。

 

正确的做法是这样的:

STL里所有的容器类的erase实现都会返回一个iterator,这个iterator指向了“当前删除元素的后继元素,或是end()”

因此,在遍历容器的所有元素过程中通过erase删除一个元素后,将erase的返回值赋给迭代变量:

//====================新代码

VectorType::iterator it = someVector.begin();
for (; it != someVector.end();)
{
      if (*it== value)
     {
          it = someVector.erase(it);
      }
      else
     {
          ++it;
     }
}

//====================

P.S. 可以看出,VS2005带的STL增加了更多的调试特性以避免出现STL的一些错误,有条件的话最好用VS2005的STL。如果没有VS2005,也可以使用STLport,STLport在调试特性上也非常出色。

 

技巧六:将vs2005的程序转到2008上,出现了如下warning

 Warning 1 Command line warning D9035 : option 'Wp64' has been deprecated and will be removed in a future release cl

原因:

vs2008不再建议使用/wp64检测64兼容问题,因为可以直接在32位OS上交叉编译为64位代码(vs2005也可以)。vs2008建议直接使用该方法检测64位兼容性问题。该选项被设置为“不推荐”有个原因是它会导致某些template库发生许多无效的warning。

解决办法:

property-->c/c++ -->Detect 64 bit Portability Issues设为No。

 

技巧七:MDI视图切换(或标签切换)时如果需要进行处理应在子框架的OnMDIActivate函数中进行

如果在视图类的OnActiveView中处理,一些操作如最小化、切换程序窗口都会触发。也不利于调试。

void CChildFrame::OnMDIActivate(BOOL bActivate, CWnd* pActivateWnd, CWnd* pDeactivateWnd)
{
     CMyView *pActiveView = NULL;
     if ( pActivateWnd )
     {
          pActiveView = (CMyView*)((CChildFrame*)pActivateWnd)->GetActiveView();
          if ( pActiveview )
          {
               /*Do Something*/
          }
    }
}

 

技巧八:关于无法打开PCH预编译头文件
vs使用中经常出现无法打开预编译头文件的情况,解决这种情况的方法是:

将工程的预编译头文件指令指定为/Yc的.CPP文件(默认为StdAfx.cpp)重新编译一次即可再次生成.PCH文件。具体选项位置为:
项目属性->C/C++->Precompiled Headers->Create/Use Precompiled Header
设定为Create Precompiled Header(/Yc).编译StdAfx.cpp结束后修改为Use Precompiled Header (/Yu)即可

 

技巧九:国际化语言实时切换的实现:

方法1:采用VC纯资源DLL解决国际化问题

实现方法参考地址:http://blog.csdn.net/i_mimi/archive/2008/05/16/2452705.aspx

方法2:采用ini配置文件方式。在注册表内写语言文件地址进行查找的方式

实现方法可参考文章:‘VC下程序多语言化’电脑编程技巧与维护 2007年11期

 

技巧十:release状态下生成代码(Generating Code)非常慢的原因

之前写一个工程遇到release状态下生成代码需要一两个小时的情况。后来发现原来是工程中有一个cpp文件代码过长(几万行),取消该文件中函数的调用。link的速度恢复正常。应该算是低级失误。。。

 

技巧十一:调试着色器比较好的IDE:

1、AMD的RenderMonkey.可以用来调试OpenGL的GLSL和微软的HLSL着色语言,虽然从08年开始停止更新。但仍是调试GLSL的不二之选。不支持CG语言

2、nVidia的FX Composer,与微软联合出品。可以用来调试英威达自己维护的CG语言和微软的HLSL。是调试CG的不二之选

3、微软DX SDK里的PIX FOR Windows  可以用来调试HLSL。据说功能很强大。没用过。不予评论。

 

技巧十二:位运算的基础知识

系统程序中常要求在位(bit)一级进行运算或处理。C语言提供了位运算的功能,这使得C语言也能像汇编语言一样用来编写系统程序。
C语言提供了六种位运算符:  
1、 &   按位与   
2、|   按位或   
3、 ^   按位异或   
4、~   取反   
5、<<   左移   
6、>>   右移   
   
1.   按位与运算   按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1   ,否则为0。参与运算的数以补码方式出现。   
例如:9&5可写算式如下:   00001001   (9的二进制补码)&00000101   (5的二进制补码) 00000001   (1的二进制补码)可见9&5=1。   
   
按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清 0 ,保留低八位,可作a&255 运算   (   255   的二进制数为0000000011111111)。 

//=====  
 main()
{  
  int   a=9,b=5,c;  
  c=a&b;  
  printf("a=%d/nb=%d/nc=%d/n",a,b,c);  
  }   
//=====  

2.   按位或运算   按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。  
  例如:9|5可写算式如下:   00001001|00000101  
  00001101   (十进制为13)可见9|5=13   

//=====  

  main(){  
  int   a=9,b=5,c;  
  c=a|b;  
  printf("a=%d/nb=%d/nc=%d/n",a,b,c);  
  }   
//=====  

3.   按位异或运算   按位异或运算符“^”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现,例如9^5可写成算式如下:   00001001^00000101   00001100   (十进制为12)   
//=====  
  main(){  
  int   a=9;  
  a=a^15;  
  printf("a=%d/n",a);  
  }   
 //=====  
   
4.   求反运算   求反运算符~为单目运算符,具有右结合性。   其功能是对参与运算的数的各二进位按位求反。例如~9的运算为:   ~(0000000000001001)结果为:1111111111110110   
   
5.   左移运算   左移运算符“<<”是双目运算符。其功能把“<<   ”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,  
  高位丢弃,低位补0。例如:   a<<4   指把a的各二进位向左移动4位。如a=00000011(十进制3),左移4位后为00110000(十进制48)。

 

6.   右移运算   右移运算符“>>”是双目运算符。其功能是把“>>   ”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数。    
  例如:设   a=15,a>>2 表示把000001111右移为00000011(十进制3)。   应该说明的是,对于有符号数,在右移时,符号位将随同移动。当为正数时,   最高位补0,而为负数时,符号位为1,最高位是补0或是补1   取决于编译系统的规定。Turbo   C和很多系统规定为补1。

 

技巧十三:OPENGL OSG DIRECTX坐标系

不论是OPENGL还是OSG,都采用是右手系,
opengl坐标系,即z轴正向朝外;y轴正向朝上;x轴正向朝右.
osg坐标系,即z轴正向朝上;y轴正向朝前;x轴正向朝右.
可以这么来说,将opengl坐标系沿x轴沿前下方旋转90度,即osg的默认坐标系.
这跟Directx是不一样的,Directx采用左手坐标系,即z轴正向朝里;y轴正向朝上;x轴正向朝右.

 

(未完待续)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值