• VS2010下如何查看类的内存布局


    用VS2010查看类的内存布局,这里用两种方法

    (1)MSVC有个隐藏的“/d1”开关,通过这个开关可以查看项目中类的内存布局情况。

    修改项目属性,添加”/d1 reportSingleClassLayoutCC”开关,表示需要查看类CC的内存布局。

    /d1 reportAllClassLayout 是查看所有类的布局,这样编译后会在输出界面上输出很多类的布局

    /d1 reportSingleClassLayoutXX,"XX"是填入你想查看的类的名字,编译后会在输出界面上输出类的布局,任何匹配它的类名都会被输出。比如想看class A,你输入了/d1reportSingleClassLayoutA,但是你会发现会编译器输出很多无关的类,如struct ABC、Class inAttribute Class dbA...因为它们的类名都包含有A这个字母。

    (2)通过添加自定义的外部工具,将类的内存布局在cmd界面上打印出来

    1、首先新建一个bat文件,可以命名为classlayout.bat,保存在VC++的目录下,就是调用了下cl.exe而已

    @echo off
    
    call "%VS120COMNTOOLS%vsvars32.bat"
    
    if "%2" == "" goto error 
    if "%1" == "" goto error
    cl.exe /nologo /w /Zs /d1reportSingleClassLayout%2 %1
    goto :eof
     
    :error
    echo Error:参数错误 - 是否划定了类名?
    goto :eof

    2、然后新建一个cpp文件,会创建通道并创建子进程执行批处理。然后捕获批处理的标准输出,并过滤内容,只输出想要的。。。

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <windows.h>
    using namespace std;
    
    char g_name[101] = {};
    
    bool CMDLine(char* cmd)
    {
        SECURITY_ATTRIBUTES sa;
        HANDLE hRead,hWrite;
    
        sa.nLength=sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = NULL;
        sa.bInheritHandle = TRUE;
        if (!CreatePipe(&hRead, &hWrite, &sa, 0))
        {
            cout << "CreatePipe失败" << endl;
            return false;
        }
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        ZeroMemory(&si, sizeof(si));
        ZeroMemory(&pi, sizeof(pi));
        si.cb = sizeof(STARTUPINFO);
        GetStartupInfo(&si);
        si.hStdError = hWrite;
        si.hStdOutput = hWrite;
        si.wShowWindow = SW_HIDE;
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        if (!CreateProcess(NULL,cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
        {
            cout << "CreateProcess失败" << endl;
            return false;
        }
        CloseHandle(hWrite);
     
        char buffer[128] = { 0 }; 
        DWORD bytesRead;
     
        bool bFindIt = false;
        bool bFindEnd = false;
        char *pBegin = NULL;
        char *pError = NULL;
    ////    ofstream ofile("c:\out2.txt", ios_base::binary);    
    
        cout << "Waiting..." << endl;
        //WaitForSingleObject(hRead,INFINITE);
        while (ReadFile(hRead, (LPVOID)&buffer, 127, &bytesRead, NULL)) 
        {    
            buffer[bytesRead] = '';
    //////        ofile << "Block:
    ";
    ////        ofile << (char*)buffer;
    ////        continue;
            
            if(pError = strstr(buffer, "error C")) //输出错误
            {
                char *pReturn = strstr(pError, "
    ");
                if(pReturn)
                {
                    *pReturn = '
    ';
                    *(pReturn+1) = '';
                }
                cout << pError << (pReturn?"":"
    ");
                continue;
            }
    
            if(!bFindIt && (pBegin = strstr(buffer, g_name)))
            {
                system("cls");
                bFindIt = true;
    
                char *pEnd = strstr(pBegin, "
    
    
    "); //每个class间至少3个
                if(pEnd)
                {
                    *(pEnd+6) = '';
                    bFindEnd = true;    
                }
    
                cout << "class" << pBegin;
                continue;
            }
    
            if(bFindIt && !bFindEnd)
            {
                char *pEnd = strstr(buffer, "
    
    
    ");
                if(pEnd)
                {
                    *(pEnd+6) = '';
                    bFindEnd = true;
                }
                
                cout << (char*)buffer;            
            }
        }
        
    ////    ofile.close();
        if(false == bFindIt)
            cout << "
    未找到class" << g_name << endl << endl;
    
        return true;
    }
    
    int main(int argc, char*argv[])
    {
        if(argc != 3)
            goto end;
    
        cout << argv[1] << endl;
        cout << argv[2] << endl;
    
        char *cppPath = argv[1];
        while(*cppPath)
            cppPath++;
        if(cppPath - argv[1] < 5 || _strnicmp(cppPath-4, ".cpp", 4))
            goto end;
        if(*argv[2] == '')
            goto end;
        else
            _snprintf(g_name, 100, " %s	", argv[2]);
    
        char cmd[201] = {};
        _snprintf(cmd, 200, "D:\VS2010\VC\bin\classlayout.bat "%s" "%s"", argv[1], argv[2]);
    
        cout<<cmd<<endl;
        CMDLine(cmd);
        system("pause");
        return 0;
    
        end:
            cout << "error: 输入参数不正确,是否已选中类名?" << endl;
            system("pause");
            return 0;
    }

    这里要添加两个system("pause");否则到时候会存在闪退的情况

    1. 里面的ofile用来将所有捕获到的内容输出到文件的,想打开它,取消里面的////注释即可!!!
    2. 里面的_snprintf(g_name, 100, " %s ", argv[2]),是为了尽可能查找到类名,若改为"class %s ",有时会找不到,因为ReadFile是按块读取的,两个块有可能从"class %s"中间断开。。。我们这样减小了这种可能,,当然,只是减小而已。
    3. 这也会过滤error warning等
    4. struct的内存布局输出前缀也是"class"
    5. 这里提醒,如果直接复制代码,需要注意代码中的那个路径要改成你电脑上的classlayout.bat文件的路径

    3、编译通过后,配置成外部工具,工具->外部工具->添加,命令:找到你的可执行文件,参数如图所示,标题任意。

    4、在使用前,确保你要查看的类所在的cpp文件编译通过,使用时,先选中你要查看的类的名字,再在工具中找到你起的名字(classlayout)就可以

    注意:

    (1)如果你的显示CreateProcess失败,你可以看下你的项目属性中字符集选用的是不是多字节字符集

    (2)如果cmd格式不对,应该也是上述设置的问题

  • 相关阅读:
    数组 滑动窗口
    爬虫案例 下载某文库付费文档 全格式
    双指针 三数之和
    双指针 四数之和
    双指针法 环形链表 II
    判断是否手机端
    C# 模拟点击
    chrome 扩展开发注意事项
    破解拖动验 证码
    //刷新任务栏图标 终止别的进程序有些程序有托盘会残留
  • 原文地址:https://www.cnblogs.com/mini-coconut/p/9301601.html
Copyright © 2020-2023  润新知