我的编译器是否将正确的代码优化成无用的崩溃代码?

时间:2014-07-26 10:48:47

标签: c++

我正在尝试编写一个函数,在多个消息框中显示系统中所有线程的拥有进程的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

为什么会这样?我是否正确认为编译器决定“变量blahzix除了在这个消息框函数中以外没有使用过,它总是等于tentry.th32OwnerProcessID所以它们也可能是同一个变量,我只是摆脱它并制作消息框改为使用那个变量。“

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

2 个答案:

答案 0 :(得分:4)

THREADENTRY32::th32OwnerProcessIDDWORD,不是字符串。将它分配给指针并将其视为字符串是没有意义的。它也是无效的(没有显式强制转换的约束违规);我很惊讶这甚至编译的方式/原因。

不要在编译器上归咎于你自己的错误。编译器错误是非常非常罕见的。

答案 1 :(得分:2)

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);