#include <windows.h>
#include <stdio.h>
WCHAR *HiveName[4] = {L"HKCR", L"HKCU", L"HKLM", L"HKU"};
int wmain( INT argc, WCHAR **argv )
{
for ( DWORD i = 0x80000000; i < 0x80000004; i++ )
wprintf(L"%lu %s\n", i, HiveName[i]);
return 0;
}
输出:
2147483648 HKCR
2147483649 HKCU
2147483650 HKLM
2147483651 HKU
为什么会这样?
答案 0 :(得分:0)
首先,正如一些程序员Dude所说,越界数组索引是undefined behavior。这意味着根据ISO C ++标准,允许编译器发出任何内容。编译器甚至可以发出加密硬盘驱动器的病毒,它仍然是符合标准的编译器。
有人说过,我对可能发生的事情有一些猜测。
在Windows上,x86用户空间进程可以使用virtual addresses from 0x00000000
to 0x7fffffff
。默认情况下,0x80000000
及更高版本是为内核保留的,尽管有多种方法可以将此值提高到3 GB。在任何情况下,似乎任何特定分配的限制都是2 GB,因此0x80000000
或更高的索引绝对不能指向有效分配的对象。然后编译器可以自由地发出代码,假设i
必须以某种方式小于0x80000000
。
在这种情况下,可能没有任何真正的“优化”。一个版本的MSVC编译器为数组索引操作输出the following:
push DWORD PTR wchar_t ** HiveName[esi*4]
此处,esi
包含索引i
。它乘以4,即sizeof(wchar_t*)
数组元素。这会溢出,并且它总是给出正确的答案,因为最重要的位总是被抛出。