【问题标题】:how can I allocate an array on the stack if the size is not known at compile time?如果在编译时大小未知,如何在堆栈上分配数组?
【发布时间】:2021-07-31 11:57:49
【问题描述】:

我正在用 Visual Studio 编写一个 c++ 程序,并且我已经编写了这段代码

DWORD GetProcIDByName(const char* procName) {
    HANDLE hSnap;
    BOOL done;
    PROCESSENTRY32 procEntry;

    ZeroMemory(&procEntry, sizeof(PROCESSENTRY32));
    procEntry.dwSize = sizeof(PROCESSENTRY32);

    hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    done = Process32First(hSnap, &procEntry);
    do {
        /* here */ char file_str[sizeof(procEntry.szExeFile)];
        int wc_convert = WideCharToMultiByte(CP_ACP, 0, procEntry.szExeFile, sizeof(procEntry.szExeFile), file_str, sizeof(file_str), NULL, NULL);
        if (_strnicmp(file_str, procName, sizeof(file_str)) == 0) {
            return procEntry.th32ProcessID;
        }
    } while (Process32Next(hSnap, &procEntry));

    return 0;
}

为了将值 procEntry.szExeFile 从 WCHAR*(宽 unicode 字符数组)转换为标准 char* 进行比较,我必须为它创建一个 char* 缓冲区。我写了一行

char file_str[sizeof(procEntry.szExeFile)]; 

后来意识到我应该为这个缓冲区使用堆内存,它会根据进程名称改变大小,但我惊讶地发现我的 Visual Studio 对这段代码没有任何问题,而且我能够构建它没有编译器错误。我还没有运行它,我可能不会运行它,因为我想如果它运行,可能会出现缓冲区溢出和未定义的行为

我没有任何问题,但我很好奇为什么我能够编写此代码而不会出现编译器错误。如果在编译时不知道进程名,如何在栈上分配这个缓冲区?

【问题讨论】:

标签: c++ compiler-errors stack dynamic-memory-allocation heap-memory


【解决方案1】:

szExeFile 字段不是动态长度。它是一个由MAX_PATH 字符组成的定长数组,包含一个以空字符结尾的字符串。

注意:

  • sizeof() 以字节为单位报告大小
  • szExeFilewchar_t 字符的数组,在你的情况下
  • wchar_t 在 Windows 上为 2 个字节。

因此,当您将char[] 数组声明为char file_str[sizeof(procEntry.szExeFile)]; 时,它将具有MAX_PATH*2 chars 的静态编译时大小。在这种情况下,它应该足够大以轻松处理从wchar_t[]char[] 的大多数转换。

顺便说一句,您在WideCharToMultiByte() 的第四个参数中使用sizeof(procEntry.szExeFile) 是错误的。该参数需要 character 计数,而不是 byte 计数。请改用lstrlenW(procEntry.szExeFile)wcslen(procEntry.szExeFile)。或者只是 -1 让WideCharToMultiByte() 为您计算宽字符。

话虽如此,更简单的解决方案是改用Process32FirstA()/Process32NextA()。或者,更改您的函数以将 Unicode wchar_t 字符串作为输入。无论哪种方式,您都无需转换 procEntry.szExeFile,只需按原样使用即可。

另外,您正在从CreateToolhelp32Snapshot() 泄漏HANDLE,您需要在使用完毕后调用CloseHandle()

试试这个:

DWORD GetProcIDByName(const char* procName) {
    DWORD dwProcessID = 0;

    PROCESSENTRY32A procEntry = {};
    procEntry.dwSize = sizeof(procEntry);
   
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE) {
        BOOL ok = Process32FirstA(hSnap, &procEntry);
        while (ok) {
            if (_stricmp(procEntry.szExeFile, procName) == 0) {
                dwProcessID = procEntry.th32ProcessID;
                break;
            }
            ok = Process32NextA(hSnap, &procEntry);
        }
        CloseHandle(hSnap);
    }

    return dwProcessID;
}

或者这个:

DWORD GetProcIDByName(const wchar_t* procName) {
    DWORD dwProcessID = 0;

    PROCESSENTRY32W procEntry = {};
    procEntry.dwSize = sizeof(procEntry);
   
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE) {
        BOOL ok = Process32FirstW(hSnap, &procEntry);
        while (ok) {
            if (_wcsicmp(procEntry.szExeFile, procName) == 0) {
                dwProcessID = procEntry.th32ProcessID;
                break;
            }
            ok = Process32NextW(hSnap, &procEntry);
        }
        CloseHandle(hSnap);
    }

    return dwProcessID;
}

【讨论】:

  • 惊人的答案非常感谢。如果可以的话,我会投票 100 次。这很有意义。我完成的程序也因运行时错误而失败,因此句柄泄漏可能是问题的一部分。谢谢!
猜你喜欢
  • 2013-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-11
  • 2013-09-25
  • 1970-01-01
  • 2012-03-24
  • 2014-12-31
相关资源
最近更新 更多