随笔 - 5, 文章 - 0, 评论 - 13, 引用 - 0
数据加载中……

2010年3月21日

VC 单步调试(StepInto)的一个小技巧

  相对于Java之类的语言,缺少库一直是C++最为诟病的一个部分。STL、Boost等库的出现,在一定程度上弥补了这些缺憾。但这些库带来便利性的同时,也在调试代码时带来相当的不便。
  举个例子,看下面一段代码:
 
struct FooObj
{
    
char lower(char c){
        c 
|= 0x20;
        
return c;
    }
};

string s="Ok";
shared_ptr
<FooObj> ptr(new FooObj);
s[
0]=ptr->lower(s[0]);
  在s[0]=ptr->lower(s[0]); 这一行下断点,想F11 StepInto进入lower函数调试,却不得不先进入std::basic_string的[],然后再进入boost::shared_ptr,最后才真正进入我们想要调试的lower函数。这是相当的烦人。
  虽然可以在调试时,使用右键菜单中的Step Into Specific直接进入lower函数,但也很繁琐。


  我们可以在注册表中设置来避免vc 单步调试进入某些函数。具体的位置在:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\NativeDE\StepOver
  其中vc2008是9.0,如果用的是其他版本的vc,则改成相应的版本号。在这个key下面新建两个字符串:
"boost"="boost\\:\\:.*=NoStepInto"
"std"="std\\:\\:basic_string.*=NoStepInto"
  其中字符串值的含义:funcname=action,funcname是函数的名字,用正则表达式匹配, action则是执行的动作,可以是NoStepInto
或者StepInto(当action是NoStepInto时,可以省略)。NoStepInto表示当遇到这个名字的函数时,单步调试不会进入到函数内部。注意的是,函数必须是包含命名空间的原始名字。就是说,它并不能匹配typedef内容。string是std命名空间中的一个basic_string,那么字符串值必须是basic_string,而不能是string。
  这是我的
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\NativeDE\StepOver下的内容:


  Ok,现在完美了,在
s[0]=ptr->lower(s[0])这一行,按F11,进入的是我们想进入的lower函数,而不是stl或者boost中的内容。另一方面当我们偶然想跟入库函数,也可以使用Step Into Specific来达到目的。

posted @ 2010-03-21 15:24 clane 阅读(3728) | 评论 (0)编辑 收藏

2010年3月10日

vc2008 fstream不支持中文路径的解决方案

     项目编译后给朋友试运行,发现运行出错,提示路径不正确找不到配置文件。因为朋友是放在桌面运行的,于是推测是中文路径的问题(因为路径中包含"桌面"两个汉字)。反应很诧异,什么年代了,还有中文路径的问题...
     跟踪了一下ifstream的open函数,发现ifstream在打开文件之前会通过_mbstowcs_l_helper函数把文件路径从mutilbyte转换到unicode。其中的关键转换函数如下:
 if (_loc_update.GetLocaleT()->locinfo->lc_handle[LC_CTYPE] == _CLOCALEHANDLE)
        {
            
/* C locale: easy and fast */
            
while (count < n)
            {
                
*pwcs = (wchar_t) ((unsigned char)s[count]);
                
if (!s[count])
                    
return count;
                count
++;
                pwcs
++;
            }
            
return count;

        } 
    而vc的默认local信息就是_CLOCALEHANDLE,于是中文字符很悲剧的被转换成了莫名其妙的一串东西。google了下,似乎很多人碰到了这个问题,也没有特别好的解决方案,要不直接unicode,要不每次调用fstream前后都调用一遍setlocal,对代码的侵入性都很强。
    我做了个封装的解决方案,使用个模板类对fstream做一个wrapper,代码如下:
template<class T>
struct fstream_fix
    :
public T
{
    fstream_fix(){};

    template
<class T1>
    fstream_fix(T1 v1){
        setlocale(LC_CTYPE, 
".936");
        T::open(v1);
        setlocale(LC_CTYPE, 
0);
    }

    template
<class T1,class T2>
    fstream_fix(T1 v1,T2 v2){
        setlocale(LC_CTYPE, 
".936");
        T::open(v1,v2);
        setlocale(LC_CTYPE, 
0);
    }


    template
<class T1>
    
void open(T1 v1){
        setlocale(LC_CTYPE, 
".936");
        T::open(v1);
        setlocale(LC_CTYPE, 
0);
    }

    template
<class T1,class T2>
    
void open(T1 v1,T2 v2){
        setlocale(LC_CTYPE, 
".936");
        T::open(v1,v2);
        setlocale(LC_CTYPE, 
0);
    }
};

#define ifstream fstream_fix<ifstream>
#define ofstream fstream_fix<ofstream>
    OK.完美,对原项目没有任何影响,ifstream fi(filepath);filepath中含有中文也能正常工作了。:) 当然要注意的是,在宏定义之后,就不能再include <fstream>,不然可能会有编译错误。



posted @ 2010-03-10 19:19 clane 阅读(3822) | 评论 (5)编辑 收藏

2010年3月9日

IncrediBuild 30天试用过期破解清零工具

    IncrediBuild是一个协同编译工具,对于大型vc项目来说,几乎是一个必备品。废话不多说,基本上有几台电脑装了IncrediBuild,编译速度就是原来的几倍,很强很暴力。
    IncrediBuild有30天的试用期限,到期后就不能使用。很久以前做过一个时间清零工具,有需要的同学可以下载试用。当然如果是公司用户,建议还是说服部门主管去买一套,绝对物有所值。
    执行Clear的时候,会搜索整个注册表,速度有点慢,特别是电脑差的同学,不要以为是crash了,耐心等等就好。:)第一次执行之后会在目录下生成一个key.txt,以后每次打开程序,就会自动清零时间,而不用执行Clear。

PS:安装新版本的IncrediBuild后,需要重新执行Clear,搜索整个注册表。

下载地址:http://www.cppblog.com/Files/clane/xbuildcrack.zip

posted @ 2010-03-09 16:40 clane 阅读(10246) | 评论 (5)编辑 收藏

2009年2月23日

vc编译期的常量除法优化

在vc release模式下调试时,经常可以看到下面形式的汇编代码:
00FB1202  mov         ecx,dword ptr ds:[00FB543Ch] 
00FB1208  sub         ecx,dword ptr ds:[00FB5438h] 
00FB120E  mov         eax,66666667h 
00FB1213  imul        ecx  
00FB1215  sar         edx,
5 
00FB1218  mov         ecx,edx 
00FB121A  shr         ecx,1Fh 
00FB121D  add         ecx,edx 
其实这是当被除数是常量时除法的编译器优化。x/50h
优化方法是把除法转换成乘以被除数然后右移.
x/y =>  x*(1 /y) =>  x* ((1<<37) /((1<<37)* y) ) =>x * ((1<<37)/ y)>>37
为了取整效果,最终结果将会是
x/y = x * ((1<<37 +y-1 )/ y)>>37
由于y 是常量,在编译期,编译器就可以计算出((1<<37 +y-1 )/ y)的值。
那么实际计算时,编译期就可以把 x/y 转换成 x *M >> 37, M =
((1<<37 +y-1 )/ y)
除以0x50 M = (1<<37 + 0x4F)/0x50 = 0x
66666667
那么x / 0x50相当于 (x*
0x66666667)>>37

posted @ 2009-02-23 00:16 clane 阅读(1398) | 评论 (1)编辑 收藏

2009年1月8日

luabind的converter和policy

     摘要:       现在的C++设计,为了保证健壮性和复用性,特别是GP的流行,往往应用了大量的模板,容器,智能指针。但这对与LUA绑定来说绝对不是一个好消息,非常的烦琐。个人觉得,在第三方的绑定库里面,luabind和现代C++设计结合最好,也是灵活性最高的一个绑定库。      lu...  阅读全文

posted @ 2009-01-08 17:10 clane 阅读(2681) | 评论 (2)编辑 收藏