面对现实,超越自己
逆水行舟,不进则退
posts - 269,comments - 32,trackbacks - 0
代码如下:
BOOL CCommonFun::PictureWindows(const CString &strPicFile, CString &sError)
{
    CString strSystemDir="";
    ::GetSystemDirectory(strSystemDir.GetBuffer(256), 256);
    strSystemDir.ReleaseBuffer();

    CString strRundll = strSystemDir + "\\rundll32.exe";

    CString strParm;
    strParm.Format("%s//shimgvw.dll imageview_fullscreen %s", strSystemDir, strPicFile); 

    HINSTANCE hNewExe = ShellExecute(NULL, "Open", strRundll, strParm, NULL, SW_SHOW);
    if ((DWORD)hNewExe <= 32)
    {
        CString sFormat;
        sFormat.Format("return value:%d\n", (DWORD)hNewExe);
        sError = sFormat;
        return FALSE;
    }
    return TRUE;
}
posted @ 2014-03-25 18:40 王海光 阅读(615) | 评论 (0)编辑 收藏
禁用关闭按钮

在 WM_CREATE 消息处理程序中的 MDI 子框架窗口 (CMDIChildWnd 派生类) 禁用在关闭按钮使用下面的代码:

CMenu *pSysMenu = GetSystemMenu(FALSE); 
ASSERT(pSysMenu 
!= NULL); 
VERIFY(pSysMenu
->RemoveMenu(SC_CLOSE, MF_BYCOMMAND));

此时的最大、最小化、还原按钮也消失不见。通过在PreCreateWindow函数中修改来实现显示最大、最小化、还原按钮。
cs.style += WS_MINIMIZEBOX|WS_SIZEBOX; 

posted @ 2014-03-25 18:37 王海光 阅读(2639) | 评论 (0)编辑 收藏

视图类调用非模态对话时,如何销毁分配的内存

简要步骤:

1视图类在调用非模态对话框时,将自身的指针传递给非模态对话框。
2当非模态对话框结束时,向视图类发送自定义消息,由自定义消息处理函数来释放内存。

具体代码步骤:

1定义自定义消息  #define WM_RELEASEPLAYSOUNDDC (WM_USER+1001)
2修改非模态对话框类的构造函数,便于将视图指针传递进去。

非模态对话框.h文件中

class CTestDialog : public CDialog
{
    DECLARE_DYNAMIC(CPlaySound)

public:
    //CTestDialog (CWnd* pParent = NULL);   // standard constructor
    CTestDialog (CView* pParent);   // standard constructor
    virtual ~CTestDialog ();
    CView *pView;

// Dialog Data
    enum { IDD = IDD_TEST_DIALOG };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg LRESULT OnNcHitTest(CPoint point);

};

非模态对话框.cpp文件中

IMPLEMENT_DYNAMIC(CTestDialog, CDialog)
//CTestDialog::CTestDialog(CWnd* pParent /*=NULL*/)
CTestDialog::CTestDialog(CView* pParent)
    : CDialog(CTestDialog::IDD, pParent)
{
    pView = pParent;
}

3、在非模态对话框结束的时候发送自定义消息
void CTestDialog::OnBnClickedBtnClose()
{
    // TODO: Add your control notification handler code here
    pView->PostMessage(WM_RELEASEPLAYSOUNDDC, 0, 0);
    OnOK();
}

4、在视图类.h文件中,增加定义:
afx_msg LRESULT OnReleaseDialog(WPARAM wparam,LPARAM lparam);

5、在视图类.cpp文件中,增加消息映射部分:
ON_MESSAGE(WM_DIALOGOK,OnDialogOk)

6、在视图类.cpp文件中定义消息处理函数的实现:

LRESULT CTestView::OnReleaseDialog(WPARAM wparam,LPARAM lparam)
{
    if (m_pPlaySound != NULL)
    {
        delete m_pPlaySound;
        m_pPlaySound = NULL;
    }

    return 0;
}
posted @ 2014-03-07 15:01 王海光 阅读(1703) | 评论 (0)编辑 收藏

2.在你将要使用GDI+的工程中,完成初始化工作:
StdAfx.h中加入

#define ULONG_PTR unsigned long
#include <Gdiplus.h>
using namespace Gdiplus;

3.在CXApp头文件中加入

ULONG_PTR        m_gdiplusToken;

 4.在 BOOL CXApp::InitInstance() 中添加

GdiplusStartupInput     m_gdiplusStartupInput;
GdiplusStartup(&m_gdiplusToken&m_gdiplusStartupInput, NULL);

 5.在int CXApp::ExitInstance()加入(这个方法需要自己加入 在ClassWizard 中,注意在ClassName中选择CXApp,Messages列表框中选择ExitInstance)

Gdiplus::GdiplusShutdown(m_gdiplusToken);

 6.在Project->stting->Link->Intput->Additional Dependencies中加入gdiplus.lib

此时GDI+设置成功。

具体代码如下:

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)   
{   
UINT num = 0;                     // number of image encoders   
UINT size = 0;                   // size of the image encoder array in bytes   
ImageCodecInfo* pImageCodecInfo = NULL;   
GetImageEncodersSize(&num, &size);   
if(size == 0)   
return -1;     //   Failure   
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));   
if(pImageCodecInfo == NULL)   
return -1;     //   Failure   
GetImageEncoders(num, size, pImageCodecInfo);   
for(UINT j = 0; j < num; ++j)   
{   
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )   
{   
*pClsid = pImageCodecInfo[j].Clsid;   
free(pImageCodecInfo);   
return j;     //   Success   
}           
}   
free(pImageCodecInfo);   
return -1;     //   Failure   
}
void SaveFile(Bitmap* pImage, const wchar_t* pFileName)
{
EncoderParameters encoderParameters;
CLSID jpgClsid
GetEncoderClsid(L"image/jpeg", &jpgClsid);
encoderParameters.Count = 1;
encoderParameters.Parameter[0].Guid = EncoderQuality;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;
// Save the image as a JPEG with quality level 100.
ULONG             quality;
quality = 100;
encoderParameters.Parameter[0].Value = &quality;
Status status = pImage->Save(pFileName, &jpgClsid, &encoderParameters);
if (status != Ok
{
wprintf(L"%d Attempt to save %s failed./n", status, pFileName);
}
}

//调用方式:
Bitmap newbitmap(L"d://d.bmp");//加载BMP
const wchar_t *pFileName=L"d://new.jpg";//保存路径
SaveFile(&newbitmap,pFileName );

本文转自:
http://blog.csdn.net/highyyy/article/details/6125763

 

posted @ 2014-01-09 14:30 王海光 阅读(1381) | 评论 (0)编辑 收藏
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,和xml类似,本文主要对VS2008中使用Jsoncpp解析json的方法做一下记录。
Jsoncpp是个跨平台的开源库,下载地址:http://sourceforge.net/projects/jsoncpp/,我下载的是v0.5.0,压缩包大约104K。

方法一:使用Jsoncpp生成的lib文件
      解压上面下载的Jsoncpp文件,在jsoncpp-src-0.5.0/makefiles/vs71目录里找到jsoncpp.sln,用VS2008版本编译,默认生成静态链接库。 在工程中引用,只需要包含include/json下的头文件及生成的.lib文件即可。
      如何包含lib文件:在.cpp文件中#pragma comment(lib."json_vc71_libmt.lib"),在工程属性中Linker下Input中Additional Dependencies写入lib文件名字(Release下为json_vc71_libmt.lib,Debug为json_vc71_libmtd.lib

注意:Jsoncpp的lib工程编译选项要和VS工程中的编译选项保持一致。如lib文件工程编译选项为MT(或MTd),VS工程中也要选择MT(或MTd),否则会出现编译错误问题,debug和release下生成的lib文件名字不同,注意不要看错了,当成一个文件来使用(我就犯了这个错误)。

方法二:使用Jsoncpp包中的.cpp.h文件
      解压上面下载的Jsoncpp文件,把jsoncpp-src-0.5.0文件拷贝到工程目录下,jsoncpp-src-0.5.0\jsoncpp-src-0.5.0\include\jsonjsoncpp-src-0.5.0\jsoncpp-src-0.5.0\src\lib_json目录里的文件包含到VS工程中,在VS工程的属性C/C++下General中Additional Include Directories包含头文件目录.\jsoncpp-src-0.5.0\include。在使用的cpp文件中包含json头文件即可,如:#include "json/json.h"。将json_reader.cpp、json_value.cpp和json_writer.cpp三个文件的Precompiled Header属性设置为Not Using Precompiled Headers否则编译会出现错误。

jsoncpp 使用详解

jsoncpp 主要包含三种类型的 class:Value、Reader、Writer。jsoncpp 中所有对象、类名都在 namespace Json 中,包含 json.h 即可。

Json::Value 只能处理 ANSI 类型的字符串,如果 C++ 程序是用 Unicode 编码的,最好加一个 Adapt 类来适配。


下面是从网上找的代码示例:
1. 从字符串解析json
    const char* str = "{\"uploadid\": \"UP000000\",\"code\": 100,\"msg\": \"\",\"files\": \"\"}";  

    Json::Reader reader;  
    Json::Value root;  
    if (reader.parse(str, root))  // reader将Json字符串解析到root,root将包含Json里所有子元素  
    {  
        std::string upload_id = root["uploadid"].asString();  // 访问节点,upload_id = "UP000000"  
        int code = root["code"].asInt();    // 访问节点,code = 100 
    }  
2. 从文件解析json
int ReadJsonFromFile(const char* filename)  
{  
    Json::Reader reader;// 解析json用Json::Reader   
    Json::Value root; // Json::Value是一种很重要的类型,可以代表任意类型。如int, string, object, array         

    std::ifstream is;  
    is.open (filename, std::ios::binary );    
    if (reader.parse(is, root, FALSE))  
    {  
        std::string code;  
        if (!root["files"].isNull())  // 访问节点,Access an object value by name, create a null member if it does not exist.  
            code = root["uploadid"].asString();  
        
        code = root.get("uploadid", "null").asString();// 访问节点,Return the member named key if it exist, defaultValue otherwise.    

        int file_size = root["files"].size();  // 得到"files"的数组个数  
        for(int i = 0; i < file_size; ++i)  // 遍历数组  
        {  
            Json::Value val_image = root["files"][i]["images"];  
            int image_size = val_image.size();  
            for(int j = 0; j < image_size; ++j)  
            {  
                std::string type = val_image[j]["type"].asString();  
                std::string url  = val_image[j]["url"].asString(); 
                printf("type : %s, url : %s \n", type.c_str(), url.c_str());
            }  
        }  
    }  
    is.close();  

    return 0;  
3. 向文件中插入json
void WriteJsonData(const char* filename)
{
    Json::Reader reader;  
    Json::Value root; // Json::Value是一种很重要的类型,可以代表任意类型。如int, string, object, array        

    std::ifstream is;  
    is.open (filename, std::ios::binary );    
    if (reader.parse(is, root))  
    {  
        Json::Value arrayObj;   // 构建对象  
        Json::Value new_item, new_item1;  
        new_item["date"] = "2011-11-11";  
        new_item1["time"] = "11:11:11";  
        arrayObj.append(new_item);  // 插入数组成员  
        arrayObj.append(new_item1); // 插入数组成员  
        int file_size = root["files"].size();  
        for(int i = 0; i < file_size; ++i)  
            root["files"][i]["exifs"] = arrayObj;   // 插入原json中 
        std::string out = root.toStyledString();  
        // 输出无格式json字符串  
        Json::FastWriter writer;  
        std::string strWrite = writer.write(root);
        std::ofstream ofs;
        ofs.open("test_write.json");
        ofs << strWrite;
        ofs.close();
    }  

    is.close();  
}

下面是我写的使用Jsoncpp生成lib文件的工程示例:Jsoncpp测试代码,使用VS2008编译通过。
posted @ 2013-12-26 15:59 王海光 阅读(123272) | 评论 (6)编辑 收藏
一、修改标题
方法1:在CMainFrame中PreCreateWindow(CREATESTRUCT& cs)进行更改,如下:
BOOL CKTLXSubjectShowFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Add your specialized code here and/or call the base class
    cs.style &=~WS_MAXIMIZEBOX;//禁用最大化按钮
    cs.style &=~WS_SIZEBOX;
    cs.style &=~FWS_ADDTOTITLE;

    cs.lpszName = _T("测试标题");
    cs.cx = 970;
    cs.cy = 650;
    return CXTPFrameWnd::PreCreateWindow(cs);
}

方法2:在doc类中OnNewDocument函数修改,添加修改的标题,如下:
BOOL CKTLXSubjectShowDoc::OnNewDocument()
{
    if (!CDocument::OnNewDocument())
        return FALSE;

    SetTitle(_T("测试标题"));

    return TRUE;
}

二、修改标题后半部分
单文档标题通常会有两部分组成,例如:标题名称—工程名称,修改StringTable的IDR_MAINFRAME的标题,将第一个\n之前的字符串替换为

标题\n\nTestSingleTitle\n\n\nTestSingleTitle.Document\nTestSingleTitle.Document

 三、去掉标题的后半部分

方法1:在CTestSingleTitleApp::InitInstance()中调用如下语句m_pMainWnd->SetWindowText(_T("标题"));或在其他地方用(AfxGetMainWnd())->SetWindowText(_T("标题"));也可以得到相同的结果。

 

方法2:可以通过利用CWnd::SetWindowText即:void SetWindowText( LPCTSTR lpszString );重载CFramWnd类的OnUpdateFrameTitle函数

void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
    // TODO: 在此添加专用代码和/或调用基类 
    SetWindowText(_T("标题"));
    CFrameWnd::OnUpdateFrameTitle(bAddToTitle);
}

 方法3:在CMainFramePreCreateWindow函数中修改窗口风格:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
          cs.style &= ~(LONG) FWS_ADDTOTITLE;
          return CFrameWnd::PreCreateWindow(cs);
}
posted @ 2013-12-13 10:28 王海光 阅读(7351) | 评论 (1)编辑 收藏
     摘要: dstat & sar

iostat, vmstat, ifstat 三合一的工具,用来查看系统性能(我在《性能调优攻略》中提到过那三个xxstat工具)。

slurm

查看网络流量的一个工具  阅读全文
posted @ 2013-12-06 17:32 王海光 阅读(659) | 评论 (0)编辑 收藏
PreTranslateMessage(MSG* pMsg)中调用DoModal()模态窗口如下:

 1 BOOL CMainDlg::PreTranslateMessage(MSG* pMsg)
 2 {
 3     // TODO: Add your specialized code here and/or call the base class
 4     if ( pMsg->message == WM_LBUTTONDOWN)
 5     {
 6         GetWindowRect(m_oldRect);
 7         ::SetCapture(this->m_hWnd);
 8         m_bCanDrag = TRUE;
 9         m_lastPt = pMsg->pt ;
10     }
11     else if ( pMsg->message == WM_LBUTTONUP)
12     {
13         if( m_bCanDrag )
14         {
15             ::ReleaseCapture();
16             m_bCanDrag = FALSE;
17             GetWindowRect(m_newRect);
18             if (m_oldRect.EqualRect(m_newRect))
19             {
20                 GetMainItemID(pMsg);//调用对话框函数
21                 //return TRUE;
22             }
23         }
24     } 
25     else if( pMsg->message == WM_MOUSEMOVE)
26     {
27         if( m_bCanDrag )
28         {
29             CRect rc;
30             GetWindowRect(&rc);
31             rc.OffsetRect( pMsg->pt.x - m_lastPt.x , pMsg->pt.y - m_lastPt.y  ) ;
32             m_lastPt = pMsg->pt;
33             this->MoveWindow( rc );
34         }
35     }
36 
37     return CDialog::PreTranslateMessage(pMsg);
38 }

39  void CMainDlg::GetMainItemID(MSG* pMsg)
40 {
41     if (pMsg->hwnd == GetDlgItem( IDC_BTN_MYCOMPUTER )->m_hWnd)
42     {
43        CTestDlg dlg;
44        dlg.DoModal();
45     }
46 }

再单击对话框上的按钮时发送断言中断,具体位置如下:


::IsWindow(m_hWnd)

函数功能:该函数确定给定的窗口句柄是否标识一个已存在的窗口。
函数原型:BOOL IsWindow(HWND hWnd);
参数:
hWnd:被测试窗口的句柄。
返回值:如果窗口句柄标识了一个已存在的窗口,返回值为非零;如果窗口句柄未标识一个已存在窗口,返回值为零。

可能原因:在PreTranslateMessage里的获取对应m_hWnd,DoModal()模态对话框退出后,m_hWnd不是有效的窗口句柄。
解决办法:处理完WM_LBUTTONUP后,需要返回TRUE。
posted @ 2013-12-05 10:58 王海光 阅读(2423) | 评论 (0)编辑 收藏

改变程序的执行
———————

    一旦使用GDB挂上被调试程序,当程序运行起来后,你可以根据自己的调试思路来动态地在GDB中更改当前被调试程序的运行线路或是其变量的值,这个强大的功能能够让你更好的调试你的程序,比如,你可以在程序的一次运行中走遍程序的所有分支。  
一、修改变量值

    修改被调试程序运行时的变量值,在GDB中很容易实现,使用GDB的print命令即可完成。如:
        (gdb) print x=4  
    x=4这个表达式是C/C++的语法,意为把变量x的值修改为4,如果你当前调试的语言是Pascal,那么你可以使用Pascal的语法:x:=4。   
    在某些时候,很有可能你的变量和GDB中的参数冲突,如:  
        (gdb) whatis width
        type = double
        (gdb) p width
        $4 = 13
        (gdb) set width=47
        Invalid syntax in expression.

    因为,set width是GDB的命令,所以,出现了“Invalid syntax in expression”的设置错误,此时,你可以使用set var命令来告诉GDB,width不是你GDB的参数,而是程序的变量名,如:  
        (gdb) set var width=47       
    另外,还可能有些情况,GDB并不报告这种错误,所以保险起见,在你改变程序变量取值时,最好都使用set var格式的GDB命令。   

二、跳转执行

    一般来说,被调试程序会按照程序代码的运行顺序依次执行。GDB提供了乱序执行的功能,也就是说,GDB可以修改程序的执行顺序,可以让程序执行随意跳跃。这个功能可以由GDB的jump命令来完:   
    jump <linespec>
    指定下一条语句的运行点。<linespce>可以是文件的行号,可以是file:line格式,可以是+num这种偏移量格式。表式着下一条运行语句从哪里开始。    
    jump <address>
    这里的<address>是代码行的内存地址。    
    注意,jump命令不会改变当前的程序栈中的内容,所以,当你从一个函数跳到另一个函数时,当函数运行完返回时进行弹栈操作时必然会发生错误,可能结果还是非常奇怪的,甚至于产生程序Core Dump。所以最好是同一个函数中进行跳转。    
    熟悉汇编的人都知道,程序运行时,有一个寄存器用于保存当前代码所在的内存地址。所以,jump命令也就是改变了这个寄存器中的值。于是,你可以使用“set $pc”来更改跳转执行的地址。如:   
    set $pc = 0x485

三、产生信号量

    使用singal命令,可以产生一个信号量给被调试的程序。如:中断信号Ctrl+C。这非常方便于程序的调试,可以在程序运行的任意位置设置断点,并在该断点用GDB产生一个信号量,这种精确地在某处产生信号非常有利程序的调试。   
    语法是:signal <singal>,UNIX的系统信号量通常从1到15。所以<singal>取值也在这个范围。    
    single命令和shell的kill命令不同,系统的kill命令发信号给被调试程序时,是由GDB截获的,而single命令所发出一信号则是直接发给被调试程序的。  

四、强制函数返回

    如果你的调试断点在某个函数中,并还有语句没有执行完。你可以使用return命令强制函数忽略还没有执行的语句并返回。    
    return
    return <expression>
    使用return命令取消当前函数的执行,并立即返回,如果指定了<expression>,那么该表达式的值会被认作函数的返回值。    
五、强制调用函数

    call <expr>
    表达式中可以一是函数,以此达到强制调用函数的目的。并显示函数的返回值,如果函数返回值是void,那么就不显示。    
    另一个相似的命令也可以完成这一功能——print,print后面可以跟表达式,所以也可以用他来调用函数,print和call的不同是,如果函数返回void,call则不显示,print则显示函数返回值,并把该值存入历史数据中。

在不同语言中使用GDB
——————————

GDB支持下列语言:C, C++, Fortran, PASCAL, Java, Chill, assembly, 和 Modula-2。一般说来,GDB会根据你所调试的程序来确定当然的调试语言,比如:发现文件名后缀为“.c”的,GDB会认为是C程序。文件名后缀为“.C, .cc, .cp, .cpp, .cxx, .c++”的,GDB会认为是C++程序。而后缀是“.f, .F”的,GDB会认为是Fortran程序,还有,后缀为如果是“.s, .S”的会认为是汇编语言。

也就是说,GDB会根据你所调试的程序的语言,来设置自己的语言环境,并让GDB的命令跟着语言环境的改变而改变。比如一些GDB命令需要用到表达式或变量时,这些表达式或变量的语法,完全是根据当前的语言环境而改变的。例如C/C++中对指针的语法是*p,而在Modula-2中则是p^。并且,如果你当前的程序是由几种不同语言一同编译成的,那到在调试过程中,GDB也能根据不同的语言自动地切换语言环境。这种跟着语言环境而改变的功能,真是体贴开发人员的一种设计。

下面是几个相关于GDB语言环境的命令:

    show language 
        查看当前的语言环境。如果GDB不能识为你所调试的编程语言,那么,C语言被认为是默认的环境。        
    info frame
        查看当前函数的程序语言。        
    info source
        查看当前文件的程序语言。    
如果GDB没有检测出当前的程序语言,那么你也可以手动设置当前的程序语言。使用set language命令即可做到。

    当set language命令后什么也不跟的话,你可以查看GDB所支持的语言种类:    
        (gdb) set language
        The currently understood settings are:
        
        local or auto    Automatic setting based on source file
        c                Use the C language
        c++              Use the C++ language
        asm              Use the Asm language
        chill            Use the Chill language
        fortran          Use the Fortran language
        java             Use the Java language
        modula-2         Use the Modula-2 language
        pascal           Use the Pascal language
        scheme           Use the Scheme language
        
    于是你可以在set language后跟上被列出来的程序语言名,来设置当前的语言环境。 

后记
——

    GDB是一个强大的命令行调试工具。大家知道命令行的强大就是在于,其可以形成执行序列,形成脚本。UNIX下的软件全是命令行的,这给程序开发提代供了极大的便利,命令行软件的优势在于,它们可以非常容易的集成在一起,使用几个简单的已有工具的命令,就可以做出一个非常强大的功能。 
    于是UNIX下的软件比Windows下的软件更能有机地结合,各自发挥各自的长处,组合成更为强劲的功能。而Windows下的图形软件基本上是各自为营,互相不能调用,很不利于各种软件的相互集成。在这里并不是要和Windows做个什么比较,所谓“寸有所长,尺有所短”,图形化工具还是有不如命令行的地方。(看到这句话时,希望各位千万再也不要认为我就是“鄙视图形界面”,和我抬杠了 )  
    我是根据版本为5.1.1的GDB所写的这篇文章,所以可能有些功能已被修改,或是又有更为强劲的功能。而且,我写得非常仓促,写得比较简略,并且,其中我已经看到有许多错别字了(我用五笔,所以错字让你看不懂),所以,我在这里对我文中的差错表示万分的歉意。  
    文中所罗列的GDB的功能时,我只是罗列了一些带用的GDB的命令和使用方法,其实,我这里只讲述的功能大约只占GDB所有功能的60%吧,详细的文档,还是请查看GDB的帮助和使用手册吧,或许,过段时间,如果我有空,我再写一篇GDB的高级使用。 
    我个人非常喜欢GDB的自动调试的功能,这个功能真的很强大,试想,我在UNIX下写个脚本,让脚本自动编译我的程序,被自动调试,并把结果报告出来,调试成功,自动checkin源码库。一个命令,编译带着调试带着checkin,多爽啊。只是GDB对自动化调试目前支持还不是很成熟,只能实现半自动化,真心期望着GDB的自动化调试功能的成熟。    
    如果各位对GDB或是别的技术问题有兴趣的话,欢迎和我讨论交流。本人目前主要在UNIX下做产品软件的开发,所以,对UNIX下的软件开发比较熟悉,当然,不单单是技术,对软件工程实施,软件设计,系统分析,项目管理我也略有心得。欢迎大家找我交流,(QQ是:753640,MSN是:haoel@hotmail.com)

本文转自:http://blog.csdn.net/haoel/article/details/2885

posted @ 2013-11-28 12:48 王海光 阅读(478) | 评论 (0)编辑 收藏

七、设置显示选项

    GDB中关于显示的选项比较多,这里我只例举大多数常用的选项。

    set print address 
    set print address on 
        打开地址输出,当程序显示函数信息时,GDB会显出函数的参数地址。系统默认为打开的,如:        
        (gdb) f
        #0  set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>")
            at input.c:530
        530         if (lquote != def_lquote)


    set print address off 
        关闭函数的参数地址显示,如:       
        (gdb) set print addr off
        (gdb) f
        #0  set_quotes (lq="<<", rq=">>") at input.c:530
        530         if (lquote != def_lquote)

    show print address 
        查看当前地址显示选项是否打开。       
    set print array 
    set print array on 
        打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。这个选项默认是关闭的。与之相关的两个命令如下,我就不再多说了。     
    set print array off 
    show print array

    set print elements <number-of-elements>
        这个选项主要是设置数组的,如果你的数组太大了,那么就可以指定一个<number-of-elements>来指定数据显示的最大长度,当到达这个长度时,GDB就不再往下显示了。如果设置为0,则表示不限制。        
    show print elements 
        查看print elements的选项信息。        
    set print null-stop <on/off>
        如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示。这个选项默认为off。  
    set print pretty on 
        如果打开printf pretty这个选项,那么当GDB显示结构体时会比较漂亮。如:

            $1 = {
              next = 0x0,
              flags = {
                sweet = 1,
                sour = 1
              },
              meat = 0x54 "Pork"
            }

    set print pretty off
        关闭printf pretty这个选项,GDB显示结构体时会如下显示:      
            $1 = {next = 0x0, flags = {sweet = 1, sour = 1}, meat = 0x54 "Pork"}        
    show print pretty 
        查看GDB是如何显示结构体的。        
    set print sevenbit-strings <on/off>
        设置字符显示,是否按“/nnn”的格式显示,如果打开,则字符串或字符数据按/nnn显示,如“/065”。   
    show print sevenbit-strings
        查看字符显示开关是否打开。         
    set print union <on/off>
        设置显示结构体时,是否显式其内的联合体数据。例如有以下数据结构:       
        typedef enum {Tree, Bug} Species;
        typedef enum {Big_tree, Acorn, Seedling} Tree_forms;
        typedef enum {Caterpillar, Cocoon, Butterfly}
                      Bug_forms;
        
        struct thing {
          Species it;
          union {
            Tree_forms tree;
            Bug_forms bug;
          } form;
        };
        
        struct thing foo = {Tree, {Acorn}};

        当打开这个开关时,执行 p foo 命令后,会如下显示:
            $1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
        
        当关闭这个开关时,执行 p foo 命令后,会如下显示:
            $1 = {it = Tree, form = {...}}

    show print union
        查看联合体数据的显示方式   
    set print object <on/off>
        在C++中,如果一个对象指针指向其派生类,如果打开这个选项,GDB会自动按照虚方法调用的规则显示输出,如果关闭这个选项的话,GDB就不管虚函数表了。这个选项默认是off。
    show print object
        查看对象选项的设置。     
    set print static-members <on/off>
        这个选项表示,当显示一个C++对象中的内容是,是否显示其中的静态数据成员。默认是on。   
    show print static-members
        查看静态数据成员选项设置。        
    set print vtbl <on/off>
        当此选项打开时,GDB将用比较规整的格式来显示虚函数表时。其默认是关闭的。       
    show print vtbl
        查看虚函数显示格式的选项。        
八、历史记录

    当你用GDB的print查看程序运行时的数据时,你每一个print都会被GDB记录下来。GDB会以$1, $2, $3 .....这样的方式为你每一个print命令编上号。于是,你可以使用这个编号访问以前的表达式,如$1。这个功能所带来的好处是,如果你先前输入了一个比较长的表达式,如果你还想查看这个表达式的值,你可以使用历史记录来访问,省去了重复输入。
九、GDB环境变量

    你可以在GDB的调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。要定义一个GDB的变量很简单只需。使用GDB的set命令。GDB的环境变量和UNIX一样,也是以$起头。如:  
    set $foo = *object_ptr 
    使用环境变量时,GDB会在你第一次使用时创建这个变量,而在以后的使用中,则直接对其賦值。环境变量没有类型,你可以给环境变量定义任一的类型。包括结构体和数组。   
    show convenience 
        该命令查看当前所设置的所有的环境变量。
        
    这是一个比较强大的功能,环境变量和程序变量的交互使用,将使得程序调试更为灵活便捷。例如:   
        set $i = 0
        print bar[$i++]->contents   
    于是,当你就不必,print bar[0]->contents, print bar[1]->contents地输入命令了。输入这样的命令后,只用敲回车,重复执行上一条语句,环境变量会自动累加,从而完成逐个输出的功能。     
十、查看寄存器

    要查看寄存器的值,很简单,可以使用如下命令:  
    info registers 
        查看寄存器的情况。(除了浮点寄存器)    
    info all-registers
        查看所有寄存器的情况。(包括浮点寄存器)   
    info registers <regname ...>
        查看所指定的寄存器的情况。       
    寄存器中放置了程序运行时的数据,比如程序当前运行的指令地址(ip),程序的当前堆栈地址(sp)等等。你同样可以使用print命令来访问寄存器的情况,只需要在寄存器名字前加一个$符号就可以了。如:p $eip。

本文转自:http://blog.csdn.net/haoel/article/details/2884

posted @ 2013-11-28 12:18 王海光 阅读(416) | 评论 (0)编辑 收藏
仅列出标题
共27页: 1 2 3 4 5 6 7 8 9 Last