windows – 解决托管和本机堆栈跟踪 – 要使用哪个API?

这是对我之前的问题的继续 – 第2阶段即可.

第一个问题在这里:Fast capture stack trace on windows / 64-bit / mixed mode

现在我已经解决了大量的堆栈跟踪,现在想知道如何解析托管堆栈帧的符号信息.

对于原生C方面,它相对简单 –

首先,您指定从哪里获取符号的过程:

HANDLE g_hProcess = GetCurrentProcess();

您可以使用代码snipet在运行时替换进程,如下所示:

g_hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,g_processId);

b = (g_hProcess != NULL );

if( !b )
    errInfo.AppendFormat(_T("Process id '%08X' is not running anymore."),g_processId );
else
    InitSymbolLoad();

并初始化符号加载:

void InitSymbolLoad()
{
    SymInitialize(g_hProcess,NULL,TRUE);
    DWORD dwFlags = SymGetOptions();
    SymSetOptions(SymGetOptions() | SYMOPT_DEFERRED_LOADS | SYMOPT_NO_IMAGE_SEARCH);
}

然后解决原生符号,不知何故这样:

extern HANDLE g_hProcess;

void StackFrame::Resolve()
{
    struct {
        union
        {
            SYMBOL_INFO symbol;
            char buf[sizeof(SYMBOL_INFO) + 1024];
        }u;
    }ImageSymbol = { 0 };

    HANDLE hProcess = g_hProcess;
    DWORD64 offsetFromSymbol = 0;

    ImageSymbol.u.symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
    ImageSymbol.u.symbol.Name[0] = 0;
    ImageSymbol.u.symbol.MaxNameLen = sizeof(ImageSymbol) - sizeof(SYMBOL_INFO);
    SYMBOL_INFO* pSymInfo = &ImageSymbol.u.symbol;

    // Get file / line of source code.
    IMAGEHLP_LINE64 lineStr = { 0 };
    lineStr.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

    function.clear();


    if( SymGetLineFromAddr64(hProcess,(DWORD64)ip,(DWORD*)&offsetFromSymbol,&lineStr) )
    {
        function = lineStr.FileName;
        function += "(";
        function += std::to_string((_ULonglong) lineStr.LineNumber).c_str();
        function += "): ";
    }

    // Successor of SymGetSymFromAddr64.
    if( SymFromAddr(hProcess,&offsetFromSymbol,pSymInfo) )
        function += ImageSymbol.u.symbol.Name;

}

这看起来像工作.

但现在也管理堆栈帧.

我找到了两个接口:

> IDebugClient / GetNameByOffset

提到:

> http://www.codeproject.com/Articles/371137/A-Mixed-Mode-Stackwalk-with-the-IDebugClient-Inter
(*)(包括示例代码)
> http://blog.steveniemitz.com/building-a-mixed-mode-stack-walker-part-1/

使用者:

> https://github.com/okigan/CrashInsight(代码未触及4年)
>混合模式stackwalk文章提供了很好的例子.

> IXCLRDATAProcess / GetRuntimeNameByAddress

>上面提到的两个链接也提到了.
>由进程黑客使用(GPL许可证,C风格)

实现似乎存在于此:

> https://github.com/dotnet/coreclr/blob/master/src/debug/daccess/daccess.cpp
(根据提交,此代码非常活跃)

> ICorProfiler / ???

(*)文章末尾提到.

方法1似乎很老式,文章(*)也提到了一些问题.

方法3可能需要对分析API进行深入分析.
我还发现了一些关于这些API的内容 – 在这里:

https://naughter.wordpress.com/2015/05/24/changes-in-the-windows-10-sdk-compared-to-windows-8-1-part-two/

· cor.h,cordebug.h/idl,CorError.h,CorHdr.h,corhlpr.h,
corprof.h/idl,corpub.h/idl & corsym.h/idl: All of these header files
have been removed. They are all the native mode COM interface to .NET.

这句话我不太明白.这些接口是否已经死亡或被替换或者发生了什么?

所以我想基于我的简要分析方法2只是好/活的API接口值得使用?您是否遇到过与这些api相关的任何问题.

在浏览了大量代码示例和接口之后,我了解到没有任何简单易用的API接口.为本机C开发的代码和API仅适用于本机C,而为托管代码开发的代码和API仅适用于托管代码.

此外还有解决堆栈跟踪的问题可能无法解决.你看 – 开发人员可以使用Jit引擎/ IL生成器动态生成代码,并将其配置 – 所以在你有“void *”/指令地址后 – 你应该立即解决符号信息,而不是之后.但是我暂时不会这样做,会认为开发人员不是太花哨的编码器而且不会一直生成和处理新的代码,FreeLibrary也不会在没有需要的情况下被调用. (如果我挂钩FreeLibrary / Jit组件,我可以稍后解决这个问题.)

解析函数名称非常简单,通过IXCLRDataProcess带来一点魔力和运气 – 我能够获得函数名称,但是 – 我想将它更深入地扩展到确切的源代码路径和代码执行的源代码行,这个变成了相当复杂的功能.

最后,我找到了执行此类操作的源代码 – 这是在这里完成的:

https://github.com/dotnet/coreclr/blob/master/src/ToolBox/SOS/Strike/util.cpp

GetLineByOffset是该文件中的函数名称.

我已经分析,重新调整并从源代码中创建了我自己的解决方案,我现在正在这里附加:

可在此处找到更新的代码:
https://sourceforge.net/projects/diagnostic/

但这里只是在某个时间点采用的相同代码的快照:

ResolveStackM.h:

#pragma once
#include <afx.h>
#pragma warning (disable: 4091)     //dbghelp.h(1544): warning C4091: 'typedef ': ignored on left of '' when no variable is declared
#include <cor.h>                    //xclrdata.h requires this
#include "xclrdata.h"               //IXCLRDataProcess
#include <atlbase.h>                //CComPtr
#include <afxstr.h>                 //CString
#include <crosscomp.h>              //TCONTEXT
#include <Dbgeng.h>                 //IDebugClient
#pragma warning (default: 4091)

class ResoveStackM
{
public:
    ResoveStackM();
    ~ResoveStackM();
    void Close(void);

    bool InitSymbolResolver(HANDLE hProcess,CString& lastError);
    bool GetMethodName(void* ip,CStringA& methodName);
    bool GetManagedFileLineInfo(void* ip,CStringA& lineInfo);

    HMODULE mscordacwks_dll;
    CComPtr<IXCLRDataProcess> clrDataProcess;
    CComPtr<ICLRDataTarget> target;

    CComPtr<IDebugClient>       debugClient;
    CComQIPtr<IDebugControl>    debugControl;
    CComQIPtr<IDebugSymbols>    debugSymbols;
    CComQIPtr<IDebugSymbols3>   debugSymbols3;
};

//
// Typically applications don't need more than one instance of this. If you do,use your own copies.
//
extern ResoveStackM g_managedStackResolver;

ResolveStackM.cpp:

#include "ResolveStackM.h"
#include <Psapi.h>                      //EnumProcessModules
#include <string>                       //to_string
#pragma comment( lib,"dbgeng.lib" )


class CLRDataTarget : public ICLRDataTarget
{
public:
    ULONG refCount;
    bool bIsWow64;
    HANDLE hProcess;

    CLRDataTarget( HANDLE _hProcess,bool _bIsWow64 ) :
        refCount(1),bIsWow64(_bIsWow64),hProcess(_hProcess)
    {
    }

    HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid,PVOID* ppvObject)
    {
        if ( IsEqualIID(riid,IID_IUnknown) || IsEqualIID(riid,__uuidof(ICLRDataTarget)) )
        {
            AddRef();
            *ppvObject = this;
            return S_OK;
        }

        *ppvObject = NULL;
        return E_NOINTERFACE;
    }

    ULONG STDMETHODCALLTYPE AddRef( void)
    {
        return ++refCount;
    }

    ULONG STDMETHODCALLTYPE Release( void)
    {
        refCount--;

        if( refCount == 0 )
            delete this;

        return refCount;
    }

    virtual HRESULT STDMETHODCALLTYPE GetMachineType( ULONG32 *machineType )
    {
        #ifdef _WIN64
            if (!bIsWow64)
                *machineType = IMAGE_FILE_MACHINE_AMD64;
            else
                *machineType = IMAGE_FILE_MACHINE_I386;
        #else
            *machineType = IMAGE_FILE_MACHINE_I386;
        #endif

        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE GetPointerSize( ULONG32* pointerSize )
    {
#ifdef _WIN64
    if (!bIsWow64)
#endif
        *pointerSize = sizeof(PVOID);
#ifdef _WIN64
    else
        *pointerSize = sizeof(ULONG);
#endif
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE GetImageBase( LPCWSTR imagePath,CLRDATA_ADDRESS *baseAddress )
    {
        HMODULE dlls[1024] = { 0 };
        DWORD nItems = 0;
        wchar_t path[ MAX_PATH ];
        DWORD whatToList = LIST_MODULES_ALL;

        if( bIsWow64 )
            whatToList = LIST_MODULES_32BIT;

        if( !EnumProcessModulesEx( hProcess,dlls,sizeof(dlls),&nItems,whatToList ) )
        {
            DWORD err = GetLastError();
            return HRESULT_FROM_WIN32(err);
        }

        nItems /= sizeof(HMODULE);
        for( unsigned int i = 0; i < nItems; i++ )
        {
            path[0] = 0;
            if( GetModuleFileNameEx(hProcess,dlls[i],path,sizeof(path) / sizeof(path[0])) )
            {
                wchar_t* pDll = wcsrchr( path,L'\\');
                if (pDll) pDll++;

                if (_wcsicmp(imagePath,path) == 0 || _wcsicmp(imagePath,pDll) == 0)
                {
                    *baseAddress = (CLRDATA_ADDRESS) dlls[i];
                    return S_OK;
                }
            }
        }
        return E_FAIL;
    }

    virtual HRESULT STDMETHODCALLTYPE ReadVirtual( CLRDATA_ADDRESS address,BYTE *buffer,ULONG32 bytesRequested,ULONG32 *bytesRead )
    {
        SIZE_T readed;

        if( !ReadProcessMemory(hProcess,(void*)address,buffer,bytesRequested,&readed) )
            return HRESULT_FROM_WIN32( GetLastError() );

        *bytesRead = (ULONG32) readed;
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE WriteVirtual( CLRDATA_ADDRESS address,ULONG32 *bytesWritten )
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE GetTLSValue( ULONG32 threadID,ULONG32 index,CLRDATA_ADDRESS *value )
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE SetTLSValue( ULONG32 threadID,CLRDATA_ADDRESS value )
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE GetCurrentThreadID( ULONG32 *threadID )
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE GetThreadContext( ULONG32 threadID,ULONG32 contextFlags,ULONG32 contextSize,BYTE *context )
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE SetThreadContext( ULONG32 threadID,BYTE *context)
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE Request( ULONG32 reqCode,ULONG32 inBufferSize,BYTE *inBuffer,ULONG32 outBufferSize,BYTE *outBuffer)
    {
        return E_NOTIMPL;
    }
}; //CLRDataTarget





ResoveStackM::ResoveStackM() :
    mscordacwks_dll(0)
{

}

ResoveStackM::~ResoveStackM()
{
    Close();
}

void ResoveStackM::Close( void )
{
    clrDataProcess.Release();
    target.Release();
    debugClient.Release();

    if( mscordacwks_dll != 0 )
    {
        FreeLibrary(mscordacwks_dll);
        mscordacwks_dll = 0;
    }
}

bool ResoveStackM::InitSymbolResolver(HANDLE hProcess,CString& lastError)
{
    wchar_t path[ MAX_PATH ] = { 0 };

    // According to process hacker - mscoree.dll must be loaded before loading mscordacwks.dll.
    // It's enough if base application is managed.

    if( GetWindowsDirectoryW(path,sizeof(path)/sizeof(wchar_t) ) == 0 )
        return false;   //Unlikely to fail.

#ifdef _WIN64
    wcscat(path,L"\\Microsoft.NET\\Framework64\\v4.0.30319\\mscordacwks.dll");
#else
    wcscat(path,L"\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll");
#endif

    mscordacwks_dll = LoadLibraryW(path);
    PFN_CLRDataCreateInstance pCLRCreateInstance = 0;

    if( mscordacwks_dll != 0 )
        pCLRCreateInstance = (PFN_CLRDataCreateInstance) GetProcAddress(mscordacwks_dll,"CLRDataCreateInstance");

    if( mscordacwks_dll == 0 || pCLRCreateInstance == 0)
    {
        lastError.Format(L"Required dll mscordacwks.dll from .NET4 installation was not found (%s)",path);
        Close();
        return false;
    }

    BOOL isWow64 = FALSE;
    IsWow64Process(hProcess,&isWow64);
    target.Attach( new CLRDataTarget(hProcess,isWow64 != FALSE) );

    HRESULT hr = pCLRCreateInstance(__uuidof(IXCLRDataProcess),target,(void**)&clrDataProcess );

    if( FAILED(hr) )
    {
        lastError.Format(L"Failed to initialize mscordacwks.dll for symbol resolving (%08X)",hr);
        Close();
        return false;
    }

    hr = DebugCreate(__uuidof(IDebugClient),(void**)&debugClient);
    if (FAILED(hr))
    {
        lastError.Format(_T("Could retrieve symbolic debug information using dbgeng.dll (Error code: 0x%08X)"),hr);
        return false;
    }

    DWORD processId = GetProcessId(hProcess);
    const ULONG64 LOCAL_SERVER = 0;
    int flags = DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND;

    hr = debugClient->AttachProcess(LOCAL_SERVER,processId,flags);
    if (hr != S_OK)
    {
        lastError.Format(_T("Could attach to process 0x%X (Error code: 0x%08X)"),hr);
        Close();
        return false;
    }

    debugControl = debugClient;

    hr = debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
    if ((hr = debugControl->WaitForEvent(DEBUG_WAIT_DEFAULT,INFINITE)) != S_OK)
    {
        return false;
    }

    debugSymbols3 = debugClient;
    debugSymbols  = debugClient;
    // if debugSymbols3 == NULL - GetManagedFileLineInfo will not work
    return true;
} //Init

struct ImageInfo
{
    ULONG64 modBase;
};

// Based on a native offset,passed in the first argument this function
// identifies the corresponding source file name and line number.
bool ResoveStackM::GetManagedFileLineInfo( void* ip,CStringA& lineInfo )
{
    ULONG lineN = 0;
    char path[MAX_PATH];
    ULONG64 dispacement = 0;

    CComPtr<IXCLRDataMethodInstance> method;
    if (!debugSymbols || !debugSymbols3)
        return false;

    // Get managed method by address
    CLRDATA_ENUM methEnum;
    HRESULT hr = clrDataProcess->StartEnumMethodInstancesByAddress((ULONG64)ip,&methEnum);
    if( hr == S_OK )
    {
        hr = clrDataProcess->EnumMethodInstanceByAddress(&methEnum,&method);
        clrDataProcess->EndEnumMethodInstancesByAddress(methEnum);
    }

    if (!method)
        goto lDefaultFallback;

    ULONG32 ilOffsets = 0;
    hr = method->GetILOffsetsByAddress((CLRDATA_ADDRESS)ip,1,&ilOffsets);

    switch( (long)ilOffsets )
    {
        case CLRDATA_IL_OFFSET_NO_MAPPING:
            goto lDefaultFallback;

        case CLRDATA_IL_OFFSET_PROLOG:
            // Treat all of the prologue as part of the first source line.
            ilOffsets = 0;
            break;

        case CLRDATA_IL_OFFSET_EPILOG:
        {
            // Back up until we find the last real IL offset.
            CLRDATA_IL_ADDRESS_MAP mapLocal[16];
            CLRDATA_IL_ADDRESS_MAP* map = mapLocal;
            ULONG32 count = _countof(mapLocal);
            ULONG32 needed = 0;

            for( ; ; )
            {
                hr = method->GetILAddressMap(count,&needed,map);

                if ( needed <= count || map != mapLocal)
                    break;

                map = new CLRDATA_IL_ADDRESS_MAP[ needed ];
            }

            ULONG32 highestOffset = 0;
            for (unsigned i = 0; i < needed; i++)
            {
                long l = (long) map[i].ilOffset;

                if (l == CLRDATA_IL_OFFSET_NO_MAPPING || l == CLRDATA_IL_OFFSET_PROLOG || l == CLRDATA_IL_OFFSET_EPILOG )
                    continue;

                if (map[i].ilOffset > highestOffset )
                    highestOffset = map[i].ilOffset;
            } //for

            if( map != mapLocal )
                delete[] map;

            ilOffsets = highestOffset;
        }
        break;
    } //switch

    mdMethodDef methodToken;
    void* moduleBase = 0;
    {
        CComPtr<IXCLRDataModule> module;

        hr = method->GetTokenAndScope(&methodToken,&module);
        if( !module )
            goto lDefaultFallback;

        //
        // Retrieve ImageInfo associated with the IXCLRDataModule instance passed in. First look for NGENed module,second for IL modules.
        //
        for (int extentType = CLRDATA_MODULE_PREJIT_FILE; extentType >= CLRDATA_MODULE_PE_FILE; extentType--)
        {
            CLRDATA_ENUM enumExtents;
            if (module->StartEnumExtents(&enumExtents) != S_OK )
                continue;

            CLRDATA_MODULE_EXTENT extent;
            while (module->EnumExtent(&enumExtents,&extent) == S_OK)
            {
                if (extentType != extent.type )
                    continue;

                ULONG startIndex = 0;
                ULONG64 modBase = 0;

                hr = debugSymbols->GetModuleByOffset((ULONG64) extent.base,&startIndex,&modBase);
                if( FAILED(hr) )
                    continue;

                moduleBase = (void*)modBase;

                if (moduleBase )
                    break;
            }
            module->EndEnumExtents(enumExtents);

            if( moduleBase != 0 )
                break;
        } //for
    } //module scope

    DEBUG_MODULE_AND_ID id;
    DEBUG_SYMBOL_ENTRY symInfo;
    hr = debugSymbols3->GetSymbolEntryByToken((ULONG64)moduleBase,methodToken,&id);
    if( FAILED(hr) )
        goto lDefaultFallback;

    hr = debugSymbols3->GetSymbolEntryInformation(&id,&symInfo);
    if (FAILED(hr))
        goto lDefaultFallback;

    char* IlOffset = (char*)symInfo.Offset + ilOffsets;

    //
    // Source maps for managed code can end up with special 0xFEEFEE markers that
    // indicate don't-stop points.  Try and filter those out.
    //
    for (ULONG SkipCount = 64; SkipCount > 0; SkipCount--)
    {
        hr = debugSymbols3->GetLineByOffset((ULONG64)IlOffset,&lineN,sizeof(path),&dispacement );
        if( FAILED( hr ) )
            break;

        if (lineN == 0xfeefee)
            IlOffset++;
        else
            goto lCollectInfoAndReturn;
    }

    if( !FAILED(hr) )
        // Fall into the regular translation as a last-ditch effort.
        ip = IlOffset;

lDefaultFallback:
    hr = debugSymbols3->GetLineByOffset((ULONG64) ip,&dispacement);

    if( FAILED(hr) )
        return false;

lCollectInfoAndReturn:
    lineInfo += path;
    lineInfo += "(";
    lineInfo += std::to_string((_ULonglong) lineN).c_str();
    lineInfo += "): ";
    return true;
}


bool ResoveStackM::GetMethodName(void* ip,CStringA& symbol)
{
    symbol.Empty();

    GetManagedFileLineInfo(ip,symbol);

    USES_CONVERSION;
    CLRDATA_ADDRESS displacement = 0;
    ULONG32 len = 0;
    wchar_t name[1024];
    if (!clrDataProcess )
        return false;

    HRESULT hr = clrDataProcess->GetRuntimeNameByAddress( (CLRDATA_ADDRESS)ip,sizeof(name) / sizeof(name[0]),&len,name,&displacement );

    if( FAILED( hr ) )
        return false;

    name[ len ] = 0;
    symbol += W2A(name);
    return true;
} //GetMethodName



ResoveStackM g_managedStackResolver;

到目前为止只测试了一些较小的代码,只有64位(怀疑32位工作原理 – 我还没有调用堆栈确定).

这段代码可能包含错误,但我会试着困扰它们并修复它们.

我收集了很多代码,请将此答案标记为有用.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读2.2k次,点赞6次,收藏20次。在我们平时办公工作中,很多时候我们经常会使用到虚拟机来进行环境的测试,我们平时在虚拟机上接触的最多的莫过于Linux和Winwdos。不过虚拟机环境和物理机环境是无法直接传输的,那么有的时候呢,同学们又想要在两者之间相互传输文件,可能就会使用QQ邮箱等形式来传输,这样的效率又慢而且繁琐,今天我就为大家带来一种非常便捷的传输方式。通过XFTP工具来进行文件传输。_xftp连接windows
文章浏览阅读1k次。解决 Windows make command not found 和 安装 GCC 环境_windows下载gcc
文章浏览阅读3.2k次,点赞2次,收藏6次。2、鼠标依次点击“计算机配置“ - ”管理模板“ - ”网络“ - ”Lanman工作站”,点击右侧的“启用不安全的来宾登录”策略。Windows访问samba共享时,提示“你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问”1、键盘按下window+R键,输入gpedit.msc,启动本地组策略编辑器。首先在终端中输入sudo ufw status查看当前防火墙状态。默认状态是“未配置”,修改为“已启用”。示例:创建一个narada的目录在/home下。1.更新apt储存库列表。_ubuntu samba 目标文件夹访问被拒绝
文章浏览阅读1.3w次。蓝光版属于高清版的一种。BD英文全名是Blu-ray Disc,一种高清的电影版本,这种电影十分清晰但是数据量巨大,占数十G甚至上百G的容量,只有蓝光光碟才能装得下,所以这种高清电影被称为BD版。一般的高清电影多半是从蓝光电影、国外的高清电视频道上压制而来的,可以通过网络下载,多数都经过二次压缩,画质要逊于原视频,不过压缩后的容量从蓝光的25G-50G会减少成4G-8G等(15G-20G不等)。众所周知,视频有两种常见的清晰度,BD和HD,在看电影的时候最常出现这两个标志,那么BD和HD具体指的是什么呢?_bd hd
文章浏览阅读974次,点赞7次,收藏8次。提供了更强大的功能,因为它允许直接访问当前元素,而不需要类型转换。接口,它可以提供一个迭代器,用于按顺序访问集合中的元素。接口是只读的,它只能支持前向迭代,不能修改集合中的元素。类型的集合实例,并向其中添加了几个元素。接口,可以创建一个能够迭代访问泛型集合中元素的迭代器。接口,我们可以在 C# 中实现可迭代的集合,并使用。循环和迭代器手动遍历集合,并输出每个元素的值。接口表示一个可枚举的集合,它定义了一个方法。属性,用于获取集合中当前位置的元素。存储集合中的元素,并实现了。的泛型集合类,它实现了。
文章浏览阅读1.4w次,点赞5次,收藏22次。如果使用iterator的remove方法则会正常,因为iterator的remove方法会在内部调用List的remove方法,但是会修改excepedModCount的值,因此会正常运行。因为遍历过程中进行remove 操作时,该位置后面的元素会挤到前面来,这时候会发生一种情况就是原来元素的位置会被他后面的元素取代,而该位置已经遍历过了,所以该元素不会背遍历。当我们倒序遍历元素的时候,无论删除元素之后的元素怎么移动,之前的元素对应的索引(index)是不会发生变化的,所以在删除元素的时候不会发生问题。_list删除某个元素
文章浏览阅读2.9w次,点赞45次,收藏192次。Windows下配置Visual Studio _vs2022环境变量配置
文章浏览阅读7w次,点赞162次,收藏778次。pip 是Python包管理工具,提供了对 Python 包的查找、下载、安装、卸载的功能,目前Python 3.4 和 2.7 及以上版本都有配套安装,一般pip的位置在...pythonScripts文件夹里面,而在其他版本需要自行下载。_python pip install安装
文章浏览阅读5.8k次,点赞2次,收藏12次。①此电脑右击----->选择属性----->高级系统设置----->环境变量----->path----->编辑----->新建。第一个选项意思就是将安装路径填入到系统环境变量中,这里勾选,后面使用可能会出现问题,建议不要勾选,安装好之后手动添加环境变量。注意:如果提示conda不是内部或外部命令,原因是Anaconda的环境变量没配置好。如果不想立即打开anaconda,不勾选直接finish就好。②输入 conda --version ,查看conda环境。②直接按win键,搜索“环境变量”_windows安装anaconda
文章浏览阅读5.1k次,点赞8次,收藏55次。Windows 系统从零配置 Python 环境,安装CUDA、CUDNN、PyTorch 详细教程_windows cuda cudnn配置
文章浏览阅读1.5w次,点赞54次,收藏68次。macOS系统自带有VNC远程桌面,我们可以在控制端上安装配置VNC客户端,以此来实现远程控制macOS。但通常需要在不同网络下进行远程控制,为此,我们可以在macOS被控端上使用cpolar做内网穿透,映射VNC默认端口5900,通过所生成的公网地址,来实现在公网环境下远程控制VNC。_vnc mac
文章浏览阅读2.4k次,点赞5次,收藏11次。进入后根据自己的电脑系统下载,这是python 3.10版本下载地址,如果想要下载其它版本可进入此链接(下载完成后点击进行安装点击下一步,到这一步时,可以选择将Anaconda添加我的PATH环境变量中,这样就不用自己手动配置和环境变量。安装完成后,打开终端,输出 python 命令可查看是否安装成功。如果显示自己刚才安装的版本号说明安装成功。查看conda版本命令:conda info。_paddlespeech下载
文章浏览阅读3.3k次。所以如果要删除之前新增的课程编译原理,只需输入命令del Course:8:Cname,同时还应该把本课程的学分删除del Course:8:Ccredit,如下图所示;Redis并没有修改数据的命令,所以如果在Redis中要修改一条数据,只能在使用set命令时,使用同样的键值,然后用新的value值来覆盖旧的数据。先调用get命令,输出原先的值,然后set新的值,最后再get得到新值,所以修改成功。输入命令后没有报错,表示成功了,刷新windows的服务,多了一个redis服务。_redis windows服务
文章浏览阅读2.1w次,点赞9次,收藏56次。​​接着在【工作负荷】中,选择【使用C++桌面开发】 ,右边【安装详细信息】去除其它可选项,只勾选【MSVCv142 】和 【Windows 10 SDK】,按图示修改,然后右下角点击安装,之后会有提示让你重启电脑。重启电脑之后,再进行pip安装。报错原因是pip所安装的包需要使用C++编译后才能够正常安装,但是当前安装环境中缺少完整的C++编译环境,因此安装失败。3.安装Microsoft Visual C++ Build Tool离线安装包(1个多G),CSDN资源很多,需要积分下载,_error: microsoft visual c++ 14.0 or greater is required. get it with "micros
文章浏览阅读1.1w次,点赞3次,收藏7次。Step 3: 在右侧窗口中找到名称为“LongPathsEnabled”的“DWORD (32 位) 值”条目,并双击它。通过注册表方法或组策略方法启用长路径支持后,您将能够在 Windows 中使用长路径,并能够访问和处理长路径下的文件和文件夹。Step 2: 依次选择“计算机配置” > “管理模板” > “系统” > “文件资源管理器”。Step 3: 找到“启用 Win32 长路径”设置,双击它。Step 4: 选择“已启用”选项按钮,然后选择“应用”按钮。_windows长路径支持
文章浏览阅读2.5k次,点赞81次,收藏86次。
文章浏览阅读1.3k次,点赞65次,收藏50次。顺序表,链表,栈,队列,ArrayList,LinkedList,Stack,Queue
文章浏览阅读2.3k次,点赞2次,收藏2次。AnyTXTSearcher是一款能够帮助我们对文档以及文本内容进行快速搜索和管理的工具,通过该软件能够搜索各种Office文档,文本文件,代码,PDF文档等,顶级的全文搜索引擎1秒钟之内即可完成搜索。_anytxt searcher
文章浏览阅读8.8k次,点赞73次,收藏70次。有时,在删除/移动/重命名文件夹/文件时,会遇到如下警告,即使将打开的程序关闭了,后台也可能会有没关干净的相关进程。_解除占用
文章浏览阅读4.3w次,点赞91次,收藏102次。JDK(Java Development Kit)是Java开发工具包的缩写,包含了Java编译器、Java虚拟机、Java类库等众多组件,是Java开发的基石,提供了编写、编译和运行Java程序所必需的工具。同时,为了让系统能够正确识别Java环境,在开始使用JDK进行Java开发之前,需要先把JDK安装到本地计算机,并配置好相应的环境变量。本文将介绍JDK安装与环境变量配置的方法。_windows安装jdk并配置环境变量