如果在编译时不知道大小,我如何在堆栈上分配一个数组?

how can I allocate an array on the stack if the size is not known at compile time?

我正在用 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 对这段代码没有问题而且我能够在没有编译器错误的情况下构建它。我还没有 运行 它,我可能不会,因为我想如果这个 运行s 有可能出现缓冲区溢出和未定义的行为

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

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

注意:

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

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

顺便说一句,您在 WideCharToMultiByte() 的第 4 个参数中使用 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;
}