有人说:"有的女人就像c#,长得很漂亮,但家务活不行。" 呵呵,其实我倒是认为不是那个女人不行,而是那个男人不行,征服不了那个女人。C#长得的确算漂亮,如果你驾驭了它,一样能让它服服帖帖做好家务。
对于习惯C的程序员,Java之类的面向对象编程语言用着不是很爽,很多直接访问内存的操作行不通。而C#提供了指针的机制,以满足C族程序员的这点嗜好。不过刚开始了解到C#支持指针的时候,我也不以为然,总觉得这么搞显得不伦不类的。经过一番研究,慢慢感觉到了在一个有着强大基础类库的OO语言中使用指针的价值和威力。下面用代码展示一下使用指针的一些常用操作在C#中是怎么玩的,由于仅仅是展示,所以杂七杂八的代码全放在一起了。
view plaincopy to clipboardprint?
01. 1using System;
02. 2
03. 3namespace Sophy.UnsafeCode
04. 4{
05. 5 unsafe class Program
06. 6 {
07. 7 static void Main(string[] args)
08. 8 {
09. 9 //在栈上分配内存
10.10 byte* arr_on_stack = stackalloc byte[100];
11.11
12.12 //下标访问数组
13.13 for (int i = 0; i < 100; i++)
14.14 {
15.15 arr_on_stack[i] = 0;
16.16 }
17.17
18.18 //在堆上分配内存
19.19 fixed (byte* arr_on_heap = new byte[100])
20.20 {
21.21 //指针访问数组
22.22 for (int i = 0; i < 100; i++)
23.23 {
24.24 *(arr_on_heap + i) = 0;
25.25 }
26.26 }
27.27
28.28 //在栈上分配一个结构体
29.29 Point p = new Point();
30.30 //用结构体指针操作栈上的结构体
31.31 Point* pp = &p;
32.32 pp->x = 200;
33.33 (*pp).y = 300;
34.34
35.35 //在堆上分配一个结构体
36.36 fixed (byte* bs = new byte[sizeof(Point)])
37.37 {
38.38 //用结构体指针操作堆上的结构体
39.39 Point* ph = (Point*)bs;
40.40 (*ph).x = 400;
41.41 ph->y = 500;
42.42 }
43.43
44.44 //打印结构体内存地址
45.45 Console.WriteLine("pp Memory Address: 0x{0:X}.", ((int)pp).ToString());
46.46
47.47 //识别CPU字节序
48.48 pp->x = 1;
49.49 byte* pb = (byte*)&(pp->x);
50.50 if (1 == *pb)
51.51 {
52.52 Console.WriteLine("Your CPU is little endian.");
53.53 }
54.54 else if (1 == *(pb + sizeof(int) - 1))
55.55 {
56.56 Console.WriteLine("Your CPU is big endian.");
57.57 }
58.58 else
59.59 {
60.60 Console.WriteLine("Unkown.");
61.61 }
62.62 }
63.63 }
64.64
65.65 unsafe struct Point
66.66 {
67.67 public int x;
68.68 public int y;
69.69 }
70.70}
1using System;
2
3namespace Sophy.UnsafeCode
4{
5 unsafe class Program
6 {
7 static void Main(string[] args)
8 {
9 //在栈上分配内存
10 byte* arr_on_stack = stackalloc byte[100];
11
12 //下标访问数组
13 for (int i = 0; i < 100; i++)
14 {
15 arr_on_stack[i] = 0;
16 }
17
18 //在堆上分配内存
19 fixed (byte* arr_on_heap = new byte[100])
20 {
21 //指针访问数组
22 for (int i = 0; i < 100; i++)
23 {
24 *(arr_on_heap + i) = 0;
25 }
26 }
27
28 //在栈上分配一个结构体
29 Point p = new Point();
30 //用结构体指针操作栈上的结构体
31 Point* pp = &p;
32 pp->x = 200;
33 (*pp).y = 300;
34
35 //在堆上分配一个结构体
36 fixed (byte* bs = new byte[sizeof(Point)])
37 {
38 //用结构体指针操作堆上的结构体
39 Point* ph = (Point*)bs;
40 (*ph).x = 400;
41 ph->y = 500;
42 }
43
44 //打印结构体内存地址
45 Console.WriteLine("pp Memory Address: 0x{0:X}.", ((int)pp).ToString());
46
47 //识别CPU字节序
48 pp->x = 1;
49 byte* pb = (byte*)&(pp->x);
50 if (1 == *pb)
51 {
52 Console.WriteLine("Your CPU is little endian.");
53 }
54 else if (1 == *(pb + sizeof(int) - 1))
55 {
56 Console.WriteLine("Your CPU is big endian.");
57 }
58 else
59 {
60 Console.WriteLine("Unkown.");
61 }
62 }
63 }
64
65 unsafe struct Point
66 {
67 public int x;
68 public int y;
69 }
70}
在C#中想要使用指针,要给类型、方法或者代码段加上unsafe关键字,并且编译的时候要加上/unsafe选项。在Visual Studio 2005中,勾上“项目属性->生成”里的“允许不安全代码”,编译时就会自动加上/unsafe选项。
C#中的指针只能指向值类型,并且值类型中不能含有引用类型。如果允许指针指向引用类型,那将是非常令人迷惑的事情。也许你注意到了这行代码:
fixed (byte* bs = new byte[sizeof(Point)])
{
}
它把一个数组赋给了一个指针变量,数组是引用类型,那不是和上面说的矛盾了吗?其实我认为是编译器做了特殊处理,在这里直接将数组的地址赋给了指针变量。一个简单的fixed关键字,编译器在背后肯定做了不少事情。因为引用类型是在托管堆中分配的,受运行库管理,当内存中碎片太多时,垃圾回收器可能会启动内存压缩,有可能将数组移动到别的地方,这时指针指向的就不是原来的数组了,所以fixed作用还在于,把引用类型的数组“钉”在内存的那个位置上,不允许垃圾回收器移动,直到代码执行到fixed后面两个大括号之外为止。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。