在 VS 内存窗口里看 C# 变量
2022 年 1 月 14 日 · 1 分钟读完
前几篇讲的补码、浮点数、字节序,都可以在 VS 里亲眼看到。这一篇记录怎么看。
先打开不安全代码
指针只能写在 unsafe 块里,需要在项目属性里打开:项目 → 属性 → 生成 → 勾选「允许不安全代码」。SDK 风格的项目也可以直接在 .csproj 里加 <AllowUnsafeBlocks>true</AllowUnsafeBlocks>。
拿到地址,看内存
static void Main(string[] args)
{
int bst = 270;
unsafe
{
char* cp = (char*)&bst;
} // 断点打在这
}
断点停下后,在监视窗口里看 cp 就能得到地址,把地址粘到 调试 → 窗口 → 内存 里:

270 的十六进制是 0x010E,内存里却是 0E 01 00 00:低位字节在前,这就是上一篇讲的小端序。x86 和 ARM 上的 Windows 都是小端。
用指针读和改
static void Main(string[] args)
{
int bst1 = 99999;
short bst2 = 9999;
short bst3 = 9984;
unsafe
{
char* cp = (char*)&bst1;
Console.WriteLine(Convert.ToString(*cp, 16)); // 869f
*(cp + 1) = (char)34; // 改掉高 16 位
Console.WriteLine(bst1); // 2262687
char* cp2 = (char*)&bst2;
Console.WriteLine(Convert.ToString(*cp2, 16)); // 270f
*cp2 = (char)bst3;
Console.WriteLine(Convert.ToString(*cp2, 16)); // 2700
Console.WriteLine(bst2); // 9984
}
}

- 99999 是
0x0001869F,但*cp只打印出869F:因为 C# 的char占 2 个字节,char*一次读 16 位。 cp + 1不是往后挪 1 个字节,而是挪一个char,也就是 2 个字节,正好指向高 16 位。把它改成 34(0x22)后,整个数变成0x0022869F= 2262687。
指针加 1 移动的字节数等于它指向的类型的大小,这一点和 C 语言一样。
延伸
- 想按字节看,用
byte*:byte* p = (byte*)&bst;之后p[0]就是最低字节0x0E。用char*容易误会成「地址以 16 位为单位」,其实只是char有 2 字节。 - 不写 unsafe 也能看字节:
BitConverter.GetBytes(270)返回{ 0x0E, 0x01, 0x00, 0x00 };BitConverter.IsLittleEndian告诉你当前机器的字节序。.NET Core 2.1 起还有MemoryMarshal.AsBytes(new Span<int>(ref bst))这类零拷贝的写法。 - 和 PLC 打交道一定会遇到字节序:西门子 S7 是大端,上位机收到
00 01 86 9F要先反转再转 int,或者直接用BinaryPrimitives.ReadInt32BigEndian。见 西门子 PLC 通讯(一):不同数据的存储方式。 fixed:数组和字符串在托管堆上,GC 可能挪动它们,取地址前要用fixed (byte* p = array) { ... }把它钉住。
原文首发于 blog.csdn.net