是我的编译器将适当的代码优化为无用的崩溃代码

Is my compiler optimizing away proper code into useless crashing code?

本文关键字:代码优化 崩溃 代码 无用 我的 编译器      更新时间:2023-10-16

我正在尝试编写一个函数,在多个消息框中显示系统中所有线程所属进程的PID。

void CheckProcess()
{
LPCSTR blahzix;
HANDLE tsnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
THREADENTRY32 tentry;
tentry.dwSize = sizeof (tentry);
BOOL CRec = Thread32First(tsnap, &tentry);
GetLastError();
while (CRec)
{
    blahzix = tentry.th32OwnerProcessID;
    MessageBox (NULL, NULL, blahzix, MB_OK);
    CRec = Thread32Next(tsnap, &tentry);
}
CloseHandle(tsnap);
}

我对为什么这不能工作一段时间感到困惑,所以我在OllyDBG中打开它,发现MessageBox的代码有第三个参数直接接收PID数据,而不是接收一个地址,其中PID存储为字符串,导致MessageBox函数试图访问存储在00000004的数据时访问违规。如果我删除行blahzix = tentry.th32OwnerProcessID;并附加第三行,看起来像这样:LPCSTR blahzix = "anything";然后,而不是崩溃MessageBox正确显示一个标题为anything的消息框。

为什么会发生这种情况?我认为编译器决定"变量blahzix不用于任何地方,除了在这个消息框函数,它总是等于tentry。"th32OwnerProcessID所以它们可能是相同的变量,我将去掉它并让messagebox使用那个变量。"

编辑:让我重新表述一下我的问题。如果LPCSTR blahzix = "fdisaf";使用=运算符,并且=运算符应该将左侧变量的值更改为右侧数据或变量的值,那么它如何用于为blahzix创建字符串是有效的?由于blahzix显然实际上是一个指针,我认为=操作符应该只改变变量指向的位置,而不是改变其中的内容。怎么来使用=操作符在这个实例中改变它指向的字符串的数据,并在这个实例中使用它:blahzix = tentry.th32OwnerProcessID;改变指针的数据,而不是字符串的数据?=操作符不应该改变其中一个吗?如何使=运算符指定要更改的数据?

THREADENTRY32::th32OwnerProcessIDDWORD,而不是字符串。将其赋值给指针并将其作为字符串处理是没有意义的。它也是无效的(没有显式强制转换的约束违反);

不要把自己的错误归咎于编译器。编译器bug是非常非常罕见的。

blahzix = tentry.th32OwnerProcessID;

不会将整型进程id转换为字符串。它只是将进程id作为blahzix指向的地址写入。你不拥有这个地址的内存,所以试图从它显示一个字符串会导致未定义的行为。可能会发生车祸。

要通过MessageBox将进程id显示为字符串,需要将其转换为char数组。在c++ 11的支持下,你可以通过修改

blahzix = tentry.th32OwnerProcessID;
MessageBox (NULL, NULL, blahzix, MB_OK);

std::string s = std::to_string(tentry.th32OwnerProcessID);
char const *pchar = s.c_str(); 
MessageBox (NULL, NULL, pchar, MB_OK);

或者,如果您仅限于使用C(问题标记为c++,但代码都是C),您可以使用

char str[12];
sprintf(str, "%d", tentry.th32OwnerProcessID);
MessageBox (NULL, NULL, str, MB_OK);