1. Trang chủ
  2. » Công Nghệ Thông Tin

Những chủ đề tiến bộ trong C# pot

12 226 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 12
Dung lượng 120,63 KB

Nội dung

Những chủ đề tiến bộ trong C# Các mã không an toàn – Phần 2 Pointer Arithmetic Ta có thể cộng hay trừ số nguyên trên con trỏ.Ví dụ , giả sử ta có 1 con trỏ trỏ đến số nguyên,và ta thử cộng 1 vào giá trị của nó .trình biên dịch sẽ biết và tăng vùng nhớ lên 4 byte ( do kiểu int có kích thước 4 byte).nếu là kiểu double thì khi cộng 1 sẽ tăng giá trị của con trỏ lên 8 byte. ta có thể dùng toán tử +, -, +=, -=, ++,và với biến bên phía phải của toán tử này là long hay ulong Ví dụ uint u = 3; byte b = 8; double d = 10.0; uint *pUint= &u; // size of a uint is 4 byte *pByte = &b; // size of a byte is 1 double *pDouble = &d; // size of a double is 8 Giả sử địa chỉ của những con trỏ này trỏ đến là :  pUint: 1243332  pByte: 1243328  pDouble: 1243320 sau khi thi hành ta có : ++pUint; // adds 1= 4 bytes to pUint pByte -= 3; // subtracts 3=3bytes from pByte double *pDouble2 = pDouble - 4; // pDouble2 = pDouble - 32 bytes (4*8 bytes) Con trỏ sẽ có giá trị:  pUint: 1243336  pByte: 1243321  pDouble2: 1243328 Ta cũng có thể trừ 2 con trỏ với nhau .giá trị kết quả là kiểu long bằng giá trị con trỏ chia cho kích thước của kiểu mà nó đại diện .Ví dụ : double *pD1 = (double*)1243324; // note that it is perfectly valid to // initialize a pointer like this. double *pD2 = (double*)1243300; long L = pD1-pD2; // gives the result 3 (=24/sizeof(double)) Con trỏ đến Struct - Toán tử truy xuất các thành viên con trỏ Cũng giống như con trỏ trong các kiểu dữ liệu có sẵn. tuy nhiên thêm 1 điều kiện là - Struct không chứa bất kì kiểu tham chiếu nào.Do con trỏ không thể trỏ đến bất kì kiểu tham chiếu nào. để tránh điều này , trình biên dịch sẽ phất cờ lỗi nếu ta tạo ra một con trỏ đến bất kì Struct nào chứa kiểu tham chiếu . Giả sử ta có struct như sau : struct MyGroovyStruct { public long X; public float F; } Sau đó ta định nghĩa con trỏ cho nó : MyGroovyStruct *pStruct; Khởi tạo nó : MyGroovyStruct Struct = new MyGroovyStruct(); pStruct = &Struct; Cũng có thể truy xuất các giá trị thành viên của 1 struct bằng con trỏ : (*pStruct).X = 4; (*pStruct).F = 3.4f; Tuy nhiên cú pháp này hơi phức tạp. C# định nghĩa 1 toán tử khác cho phép ta truy xuất các thành viên của Struct bằng con trỏ đơn giản hơn , gọi là toán tử truy xuất thành viên con trỏ ,kí hiệu là -> Cách dùng : pStruct->X = 4; pStruct->F = 3.4f; Ta cũng có thể thiết đặt trực tiếp con trỏ của kiểu tương đương để trỏ đến các trường trong Struct long *pL = &(Struct.X); float *pF = &(Struct.F); hay : long *pL = &(pStruct->X); float *pF = &(pStruct->F); Con trỏ đến các thành viên của lớp Ta đã nói rằng không thể tạo ra con trỏ đến lớp.vì việc tạo có thể làm cho bộ gom rác hoạt động không đúng. tuy nhiên ta có thể tạo các con trỏ đến các thành viên của lớp .Ta sẽ viết lại struct của ví dụ trước như là lớp : class MyGroovyClass { public long X; public float F; } sau đó ta có thể tạo 1 con trỏ đến các trường của nó ,X và F.tuy nhiên làm như vậy sẽ gây ra lỗi : MyGroovyClass myGroovyObject = new MyGroovyClass(); long *pL = &( myGroovyObject.X); // wrong float *pF = &( myGroovyObject.F); // wrong Do X và F nằm trong 1 lớp , mà được đặt trong heap.nghĩa là chúng vẫn gián tiếp chịu sự quản lý của bộ gom rác.cụ thể bộ gom rác có thể quyết định di chuyển MyGroovyClass đến 1 vị trí mới trong bộ nhớ để dọn dẹp heap.Nếu làm điều này thì bộ gom rác tất nhiên sẽ cập nhật tất cả các tham chiếu đến đối tượng ,giả sử như biến myGrooveObject vẫn sẽ trỏ đến đúng vị trí.Tuy nhiên bộ gom rác không biết gì về con trỏ cả. vì thế nếu di chuyển các đối tượng tham chiếu bởi myGrooveObject,pL và pF sẽ vẫn không thay đôỉ và kết cuộc là trỏ đến sai vị trí vùng nhớ. Để giải quyết vấn đề này ta dùng từ khóa fixed , mà cho bộ gom rác biết rằng có thể có con trỏ trỏ đến các thành viên của các thể hiện lớp,vì thế các thể hiện lớp này sẽ không được di chuyển.cú pháp như sau nếu ta chỉ muốn khai báo 1 con trỏ : MyGroovyClass myGroovyObject = new MyGroovyClass(); // do whatever fixed (long *pObject = &( myGroovyObject.X)) { // do something } nếu ta muốn khai báo nhiều hơn 1 con trỏ ta có thể đặt nhiều câu lệnh fixed trước khối mã giống nhau : MyGroovyClass myGroovyObject = new MyGroovyClass(); fixed (long *pX = &( myGroovyObject.X)) fixed (float *pF = &( myGroovyObject.F)) { // do something } Ta có thể lồng các khối fixed nếu ta muốn fix các con trỏ trong các thời điểm khác nhau MyGroovyClass myGroovyObject = new MyGroovyClass(); fixed (long *pX = &( myGroovyObject.X)) { // do something with pX fixed (float *pF = &( myGroovyObject.F)) { // do something else with pF } } Ta cũng có thể khởi tạo vài biến trong cùng 1 khối fixed : MyGroovyClass myGroovyObject = new MyGroovyClass(); MyGroovyClass myGroovyObject2 = new MyGroovyClass(); fixed (long *pX = &( myGroovyObject.X), pX2 = &( myGroovyObject2.X)) { // etc. Thêm các lớp và Struct đến ví dụ Trong phần này ta sẽ minh họa việc tính toán trên con trỏ và các con trỏ đến struct và lớp .Ta dùng ví dụ 2, PointerPlayaround2: struct CurrencyStruct { public long Dollars; public byte Cents; public override string ToString() { return "$" + Dollars + "." + Cents; } } class CurrencyClass { public long Dollars; public byte Cents; public override string ToString() { return "$" + Dollars + "." + Cents; } } Bây giờ ta có thể áp dụng con trỏ cho các struct và lớp của ta .ta bắt đầu bằng việc trình bày kích thước của stuct , tạo ra 1 vài thể hiện của nó cùng với con trỏ.ta dùng những con trỏ này để khởi tạo 1 trong những struct Currency ,amount1. và trình bày các địa chỉ của các biến : public static unsafe void Main() { Console.WriteLine( "Size of Currency struct is " + sizeof(CurrencyStruct)); CurrencyStruct amount1, amount2; CurrencyStruct *pAmount = &amount1; long *pDollars = &(pAmount->Dollars); byte *pCents = &(pAmount->Cents); Console.WriteLine("Address of amount1 is 0x{0:X}", (uint)&amount1); Console.WriteLine("Address of amount2 is 0x{0:X}", (uint)&amount2); Console.WriteLine("Address of pAmt is 0x{0:X}", (uint)&pAmount); Console.WriteLine("Address of pDollars is 0x{0:X}", (uint)&pDollars); Console.WriteLine("Address of pCents is 0x{0:X}", (uint)&pCents); pAmount->Dollars = 20; *pCents = 50; Console.WriteLine("amount1 contains " + amount1); Ta biết rằng amount2 sẽ được lưu trữ ở 1 địa chỉ ngay sau amount1, sizeof ( CurrencyStru) trả về 16, vì vậy CurrencyStruct sẽ nằm ở địa chỉ là bội số của 4 byte.do đó sau khi giảm con trỏ currency , nó sẽ trỏ đến amount2: pAmount; // this should get it to point to amount2 Console.WriteLine("amount2 has address 0x{0:X} and contains {1}", (uint)pAmount, *pAmount); Ta trình bày nội dụng của amount2 nhưng chưa khởi tạo nó .Dù trình biên dịch C# ngăn không cho chúng ta dùng các giá trị chưa được khởi tạo nhưng khi dùng con trỏ thì điều này không còn đúng nửa.trình biên dịch không cách nào biết nội của amount2 mà ta trình bày, chỉ có ta biết. kết tiếp ta sẽ tính toán trên con trỏ pCents,pCents hiện thời trỏ đến amount1.Cents , nhưng mục đích của ta là làm cho nó trỏ đến amount2.Cents .Làm điều này ta cần giảm địa chỉ của nó.ta cần làm một vài ép kiểu : // do some clever casting to get pCents to point to cents // inside amount2 CurrencyStruct *pTempCurrency = (CurrencyStruct*)pCents; pCents = (byte*) ( pTempCurrency ); Console.WriteLine("Address of pCents is now 0x{0:X}", (uint)&pCents); Cuối cùng ta dùng vài từ khoá fixed để tạo ra một vài con trỏ mà trỏ đến các trường trong thể hiện lớp,và dùng những con trỏ này để thiết đặt giá trị của thể hiện này.Lưu ý rằng điều này cũng là lần đầu tiên ta thấy địa chỉ của một mục được lưu trữ trên heap hơn là trên stack: Console.WriteLine("\nNow with classes"); // now try it out with classes [...]... "amount3.Cents has address 0x{0:X}", (uint) pCents2); *pDollars2 = -100; Console.WriteLine("amount3 contains " + amount3); } chạy chương trình ta có : csc /unsafe PointerPlayaround2.cs Microsoft (R) Visual C# NET Compiler version 7.00.9466 for Microsoft (R) NET Framework version 1.0.3705 Copyright (C) Microsoft Corporation 2001 All rights reserved PointerPlayaround2 Size of Currency struct is 16 Address . Những chủ đề tiến bộ trong C# Các mã không an toàn – Phần 2 Pointer Arithmetic Ta có thể cộng hay trừ số. nằm trong 1 lớp , mà được đặt trong heap.nghĩa là chúng vẫn gián tiếp chịu sự quản lý của bộ gom rác.cụ thể bộ gom rác có thể quyết định di chuyển MyGroovyClass đến 1 vị trí mới trong bộ nhớ. kích thước của stuct , tạo ra 1 vài thể hiện của nó cùng với con trỏ.ta dùng những con trỏ này để khởi tạo 1 trong những struct Currency ,amount1. và trình bày các địa chỉ của các biến : public

Ngày đăng: 30/07/2014, 18:20

w