2
int p;
int i1;
int i2;
i1 = 1 << 16;
i2 = 1 << 8;
p = int(&i1)+3;

cout << hex;
cout << "&i1: " << int(&i1) << endl;
cout << "&i2: " << int(&i2) << endl;
for(int i = 0; i < 16; i++)
  cout << p << ": " << uint(*((byte*)p--)) << endl;

输出:

&i1: 12fac8
&i2: 12fabc
12facb: 0
12faca: 1
12fac9: 0
12fac8: 0
12fac7: cc
12fac6: cc
12fac5: cc
12fac4: cc
12fac3: cc
12fac2: cc
12fac1: cc
12fac0: cc
12fabf: 0
12fabe: 0
12fabd: 1
12fabc: 0

我正在使用 Visual Studio 2010 运行 Windows 7 32 位。没什么好说的,但 stackoverflow 不会让我在没有更多“细节”的情况下发布,所以这只是无用的漫谈:)

4

3 回答 3

3

当您使用该/GZ选项在 Visual C 中编译代码时,所有未初始化的堆栈变量都使用该0xcc模式设置(我怀疑是为了帮助调试)。

因此,其中的那些字节可能是 thepiintegers (a) ,或者是由使用 an 作为指针的奇怪方法创建的临时对象int,您可能需要重新考虑。

无论如何,它们存在的原因与您的特定抽象级别(C++“虚拟机”)无关一个实现可以自由地组织堆栈,但是它想要提高效率,在需要的地方插入填充。


(a)尽管i稍后在代码中声明了这一事实,但没有什么能阻止安装在函数入口处为其分配空间。大多数在幕后发生的事情都会像这样令人惊讶,因为“好像”规则是控制实现如何工作的规则。只要效果符合标准中的内容,它就可以做任何想做的事情。

于 2013-05-01T06:37:50.223 回答
1

它要么是填充,要么是未使用的临时变量。0xcc在带有调试版本的 MSVC 中,编译器生成代码以用字节填充所有变量。这有助于识别未使用的变量 - 并且选择cc不是随机选择,它有帮助,因为它是从操作系统获得的几乎不可能的地址,而且它也是int 3指令,所以如果你突然找到执行该代码的方法(例如,指向数据中某处的函数指针),代码将在那里停止。调试了一些“失控代码”问题后,我发现这是一个非常有用的功能。

它是一个相当高(或负)的数字这一事实也是有益的,因为它经常通过使其成为无效访问来显示“将变量用作索引或指针”,而不是说,如果它为零,那将是例如,数组的有效索引。

于 2013-05-01T07:56:09.963 回答
1

0xcc 来自您在调试版本中运行时。这样做是因为当您寻找缓冲区溢出等错误时,您可以轻松识别此模式

于 2013-05-01T06:38:33.067 回答