Chính xác thì IntPtr là gì?


170

Thông qua việc sử dụng IntelliSense và xem mã của người khác, tôi đã bắt gặp IntPtrloại này ; mỗi khi cần sử dụng, tôi chỉ cần đặt nullhoặc IntPtr.Zerotìm thấy hầu hết các chức năng để làm việc. Chính xác thì nó là gì và khi nào / tại sao nó được sử dụng?

Câu trả lời:


158

Đó là một số nguyên kích thước "riêng (nền tảng cụ thể)." Nó được đại diện bên trong như void*nhưng được hiển thị như một số nguyên. Bạn có thể sử dụng nó bất cứ khi nào bạn cần lưu trữ một con trỏ không được quản lý và không muốn sử dụng unsafemã. IntPtr.Zerolà hiệu quả NULL(một con trỏ null).


53
Một con trỏ là một cái gì đó trỏ đến một địa chỉ trong bộ nhớ. Trong các ngôn ngữ được quản lý, bạn có tài liệu tham khảo (địa chỉ có thể di chuyển xung quanh) trong khi trong các ngôn ngữ không được quản lý, bạn có con trỏ (địa chỉ được cố định)
Colin Mackay

93
Nói chung (trên các ngôn ngữ lập trình), một con trỏ là một số đại diện cho một vị trí vật lý trong bộ nhớ. Một con trỏ null là (hầu như luôn luôn) một con trỏ trỏ đến 0 và được công nhận rộng rãi là "không trỏ đến bất cứ thứ gì". Do các hệ thống có số lượng bộ nhớ được hỗ trợ khác nhau, nên không phải lúc nào cũng có cùng số byte để giữ số đó, vì vậy chúng tôi gọi là "số nguyên kích thước gốc" có thể giữ một con trỏ trên bất kỳ hệ thống cụ thể nào.
Sam Harwell

5
+1 cho nhận xét đó @ 280Z28, đó là lời giải thích ngắn gọn nhất về con trỏ tôi từng thấy.
BlueRaja - Daniel Pflughoeft

9
Nó được gọi là IntPtr, vì để sử dụng nó từ mã gốc không được quản lý, C / C ++, bạn sẽ phải sử dụng loại tương tự: intptr_t. IntPtr của C # ánh xạ chính xác đến intptr_t của C / C ++. Và nó có thể được thực hiện như intptr_t. Trong C / C ++, loại intptr_t được đảm bảo có cùng kích thước với loại void *.
Петър Петров

2
@Trap "Một loại dành riêng cho nền tảng được sử dụng để thể hiện con trỏ hoặc tay cầm." Không phải là "số nguyên dành riêng cho nền tảng", "cách dành riêng cho nền tảng để thể hiện con trỏ hoặc tay cầm". IntPtrcó ý nghĩa hoàn hảo, bởi vì đó là một số nguyên (như trong số nguyên toán học) và một con trỏ (như trong con trỏ). Phần Intnày ít liên quan đến kiểu int - đó là một khái niệm, không phải là một kiểu cụ thể. Mặc dù công bằng, điều duy nhất mà thông số kỹ thuật CLI nói về nó là nó thực sự là một "Số nguyên, kích thước gốc". Ồ tốt :)
Luaan

69

Đó là một loại giá trị đủ lớn để lưu trữ một địa chỉ bộ nhớ như được sử dụng trong mã gốc hoặc không an toàn, nhưng không thể sử dụng trực tiếp như một địa chỉ bộ nhớ trong mã được quản lý an toàn.

Bạn có thể sử dụng IntPtr.Sizeđể tìm hiểu xem bạn đang chạy trong quy trình 32 bit hay 64 bit, vì nó sẽ tương ứng là 4 hoặc 8 byte.


16
Điểm hay về việc phát hiện kích thước của không gian địa chỉ cho quy trình.
Noldorin

@Noldorin Đúng, nhưng không nhất thiết phải đáng tin cậy. Trước đây, có rất nhiều kiến ​​trúc có nhiều loại con trỏ và trên Windows, IntPtrcũng được sử dụng để biểu diễn các tay cầm 32 bit bất kể kiến ​​trúc (mặc dù Sizevẫn nói 8 trong trường hợp đó). Thông số CLI chỉ lưu ý rằng đó là một số nguyên có "kích thước gốc", nhưng thực sự điều đó không nói lên nhiều điều.
Luaan

@Luaan không thực sự thay đổi bất cứ điều gì trong câu trả lời của tôi phải không? IntPtr được gọi là (và được sử dụng trong toàn bộ nguồn CLR) như một giá trị đủ lớn để chứa địa chỉ bộ nhớ. Nó có thể giữ các giá trị nhỏ hơn tất nhiên. Một số kiến ​​trúc có nhiều loại con trỏ, nhưng phải có một kiểu lớn nhất của tập hợp.
Daniel Earwicker

@DanielEarwicker Vâng, đó không phải là vấn đề với bất kỳ triển khai .NET hiện tại nào, theo như tôi biết. Tuy nhiên, vấn đề (lịch sử) không chỉ là về kích thước - các con trỏ khác nhau có thể hoàn toàn không tương thích. Trong một ví dụ gần hơn với ngày hôm nay, PAE sẽ sử dụng địa chỉ 64 bit mặc dù "kích thước con trỏ riêng" vẫn là 32 bit. Nó hoàn toàn quay trở lại cuộc tranh luận "hệ thống 32-bit" nghĩa là gì? " Hiện tại chúng ta có các thanh ghi số 256 bit và 512 bit, nhưng vẫn gọi nó là 64 bit. Mặc dù bạn thực sự không thể xử lý bộ nhớ vật lý 64 bit bằng "con trỏ" 64 bit của mình. Đó là một mớ hỗn độn.
Luaan

1
Một số điều phức tạp, nhưng IntPtr vẫn là "một loại giá trị đủ lớn để lưu trữ địa chỉ bộ nhớ". Nó không lớn bằng thanh ghi phần cứng lớn nhất, để lấy một trong những ví dụ của bạn. Đó không phải là những gì nó làm. Nó đủ lớn để thể hiện một địa chỉ bộ nhớ. Sau đó, có những thứ như thế này: stackoverflow.com/questions/12006854/ , nơi chúng ta có từ "con trỏ" được sử dụng cho một cái gì đó không phải là địa chỉ bộ nhớ - đó là lý do tại sao tôi đặc biệt nói "địa chỉ bộ nhớ".
Daniel Earwicker

48

Đây là một ví dụ:

Tôi đang viết chương trình C # có giao diện với camera tốc độ cao. Máy ảnh có trình điều khiển riêng có thể tự động lấy hình ảnh và tải chúng vào bộ nhớ của máy tính.

Vì vậy, khi tôi sẵn sàng mang hình ảnh mới nhất vào chương trình của mình để làm việc, trình điều khiển máy ảnh cung cấp cho tôi một IntPtr để hình ảnh được lưu trữ trong bộ nhớ vật lý, vì vậy tôi không phải lãng phí thời gian / tài nguyên để tạo ra một hình ảnh khác khối bộ nhớ để lưu trữ một hình ảnh đã có trong bộ nhớ. IntPtr chỉ cho tôi biết hình ảnh đã ở đâu.


7
Vì vậy, đơn giản IntPtr cho phép bạn sử dụng một con trỏ không được quản lý (giống như được sử dụng trong trình điều khiển máy ảnh của bạn) trong mã được quản lý?
Callum Rogers

5
Đúng. Trong trường hợp này, rất có thể trình điều khiển máy ảnh sử dụng trình điều khiển không được quản lý dưới mui xe, nhưng để hoạt động đúng trong thế giới Chỉ quản lý, nó cung cấp IntPtr để cho phép tôi làm việc với dữ liệu một cách an toàn.
đệm

3
Vậy tại sao nó không cung cấp cho bạn một luồng (mảng byte)? Tại sao nó không an toàn hoặc không thể trả lại giá trị?
Người đàn ông Muffin

35

Giải thích trực tiếp

Một IntPtr là một số nguyên đó là kích thước tương tự như một con trỏ .

Bạn có thể sử dụng IntPtr để lưu trữ giá trị con trỏ trong loại không phải con trỏ. Tính năng này rất quan trọng trong .NET vì việc sử dụng con trỏ rất dễ bị lỗi và do đó bất hợp pháp trong hầu hết các bối cảnh. Bằng cách cho phép giá trị con trỏ được lưu trữ trong loại dữ liệu "an toàn", hệ thống ống nước giữa không an toàn các phân đoạn mã có thể được triển khai theo mã cấp cao an toàn hơn - hoặc thậm chí bằng ngôn ngữ .NET không hỗ trợ trực tiếp con trỏ.

Kích thước của IntPtr là dành riêng cho nền tảng, nhưng chi tiết này hiếm khi cần được xem xét, vì hệ thống sẽ tự động sử dụng kích thước chính xác.

Cái tên "IntPtr" khó hiểu - một cái gì đó giống như Handlecó thể phù hợp hơn. Dự đoán ban đầu của tôi là "IntPtr" là một con trỏ tới một số nguyên. Các tài liệu MSDN của IntPtr đi vào chi tiết hơi khó hiểu mà không bao giờ cung cấp cái nhìn sâu sắc hơn về ý nghĩa của tên.

Một viễn cảnh khác

An IntPtrlà một con trỏ có hai giới hạn:

  1. Nó không thể bị hủy bỏ trực tiếp
  2. Nó không biết loại dữ liệu mà nó trỏ đến.

Nói cách khác, an IntPtrgiống như mộtvoid* - nhưng với tính năng bổ sung mà nó có thể (nhưng không nên) được sử dụng cho số học con trỏ cơ bản.

Để hủy đăng ký IntPtr, bạn có thể chuyển nó thành một con trỏ thực (một thao tác chỉ có thể được thực hiện trong ngữ cảnh "không an toàn") hoặc bạn có thể chuyển nó đến một thói quen trợ giúp như InteropServices.Marshallớp được cung cấp . Việc sử dụng Marshallớp mang lại ảo tưởng về sự an toàn vì nó không yêu cầu bạn phải ở trong một bối cảnh "không an toàn" rõ ràng. Tuy nhiên, nó không loại bỏ nguy cơ sụp đổ vốn có khi sử dụng con trỏ.


2
Có một số tiền lệ cho tên "intptr" từ tiêu chuẩn C99 của ngôn ngữ lập trình "C". linux.die.net/man/3/intptr_t .
Brent Bradburn

17

Con trỏ là gì?

Trong tất cả các ngôn ngữ, con trỏ là một loại biến lưu trữ địa chỉ bộ nhớ và bạn có thể yêu cầu chúng cho bạn biết địa chỉ mà chúng đang trỏ đến hoặc giá trị tại địa chỉ mà chúng đang trỏ tới.

Một con trỏ có thể được coi là một loại dấu sách. Ngoại trừ, thay vì được sử dụng để nhảy nhanh đến một trang trong sách, một con trỏ được sử dụng để theo dõi hoặc ánh xạ các khối bộ nhớ.

Tưởng tượng chính xác bộ nhớ chương trình của bạn giống như một mảng lớn 65535 byte.

Con trỏ chỉ ngoan ngoãn

Con trỏ nhớ một địa chỉ bộ nhớ mỗi địa chỉ, và do đó chúng mỗi điểm đến một địa chỉ duy nhất trong bộ nhớ.

Là một nhóm, con trỏ nhớ và nhớ lại các địa chỉ bộ nhớ, tuân theo mọi lệnh quảng cáo lệnh của bạn.

Bạn là vua của họ.

Con trỏ trong C #

Cụ thể trong C #, một con trỏ là một biến số nguyên lưu địa chỉ bộ nhớ trong khoảng từ 0 đến 65534.

Cũng cụ thể đối với C #, các con trỏ có kiểu int và do đó được ký.

Mặc dù vậy, bạn không thể sử dụng các địa chỉ được đánh số âm, bạn cũng không thể truy cập địa chỉ trên 65534. Mọi nỗ lực để làm như vậy sẽ ném System.AccessViolationException.

Một con trỏ có tên MyPulum được khai báo như vậy:

int * MyPulum;

Một con trỏ trong C # là một int, nhưng địa chỉ bộ nhớ trong C # bắt đầu từ 0 và mở rộng đến tận 65534.

Những thứ nhọn nên được xử lý với sự chăm sóc đặc biệt

Từ không an toàn ý định làm bạn sợ, và vì một lý do rất chính đáng: Con trỏ là những thứ nhọn, và những thứ nhọn như kiếm, rìu, con trỏ, v.v. nên được xử lý đặc biệt cẩn thận.

Con trỏ cung cấp cho các lập trình viên kiểm soát chặt chẽ của một hệ thống. Do đó, những sai lầm có thể có hậu quả nghiêm trọng hơn.

Để sử dụng con trỏ, mã không an toàn phải được bật trong thuộc tính chương trình của bạn và con trỏ phải được sử dụng riêng trong các phương thức hoặc khối được đánh dấu là không an toàn.

Ví dụ về khối không an toàn

unsafe
{
    // Place code carefully and responsibly here.

}

Cách sử dụng Con trỏ

Khi các biến hoặc đối tượng được khai báo hoặc khởi tạo, chúng được lưu trữ trong bộ nhớ.

  • Khai báo một con trỏ bằng cách sử dụng tiền tố ký hiệu *.

int *MyPointer;

  • Để lấy địa chỉ của một biến, bạn sử dụng tiền tố & ký hiệu.

MyPointer = &MyVariable;

Khi một địa chỉ được gán cho một con trỏ, áp dụng như sau:

  • Không có tiền tố * để chỉ địa chỉ bộ nhớ được trỏ đến như một int.

MyPointer = &MyVariable; // Set MyPointer to point at MyVariable

  • Với tiền tố * để lấy giá trị được lưu trữ tại địa chỉ bộ nhớ được trỏ đến.

"MyPointer is pointing at " + *MyPointer;

Vì một con trỏ là một biến chứa một địa chỉ bộ nhớ, địa chỉ bộ nhớ này có thể được lưu trữ trong một biến con trỏ.

Ví dụ về con trỏ được sử dụng cẩn thận và có trách nhiệm

    public unsafe void PointerTest()
    {
        int x = 100; // Create a variable named x

        int *MyPointer = &x; // Store the address of variable named x into the pointer named MyPointer

        textBox1.Text = ((int)MyPointer).ToString(); // Displays the memory address stored in pointer named MyPointer

        textBox2.Text = (*MyPointer).ToString(); // Displays the value of the variable named x via the pointer named MyPointer.

    }

Lưu ý loại con trỏ là int. Điều này là do C # diễn giải các địa chỉ bộ nhớ dưới dạng số nguyên (int).

Tại sao nó là int thay vì uint?

Không có lý do chính đáng.

Tại sao nên sử dụng con trỏ?

Con trỏ rất nhiều niềm vui. Với rất nhiều máy tính được điều khiển bởi bộ nhớ, con trỏ trao quyền cho một lập trình viên có nhiều quyền kiểm soát bộ nhớ chương trình của họ hơn.

Theo dõi bộ nhớ.

Sử dụng các con trỏ để đọc các khối bộ nhớ và theo dõi cách các giá trị được chỉ ra thay đổi theo thời gian.

Thay đổi các giá trị này một cách có trách nhiệm và theo dõi các thay đổi của bạn ảnh hưởng đến máy tính của bạn như thế nào.


2
65534có vẻ rất sai như một phạm vi con trỏ. Bạn nên cung cấp một tài liệu tham khảo.
Brent Bradburn

1
Tôi đã bỏ phiếu này vì đây là một bài viết tuyệt vời giải thích về con trỏ. Tôi muốn xem một số tài liệu tham khảo về thông số kỹ thuật bạn đã đề cập (như đã nhận xét ở trên). Tuy nhiên; Câu trả lời này không liên quan gì đến câu hỏi. Câu hỏi là về System.IntPtr. Tôi muốn xem câu trả lời được cập nhật ở cuối giải thích những gì cũng là gì System.IntPtrvà làm thế nào nó liên quan đến con trỏ không an toàn trong C # xin vui lòng.
Michael Puckett II

7

MSDN cho chúng tôi biết:

Loại IntPtr được thiết kế thành một số nguyên có kích thước dành riêng cho nền tảng. Đó là, một thể hiện của loại này dự kiến ​​là 32 bit trên hệ điều hành và phần cứng 32 bit và 64 bit trên hệ điều hành và phần cứng 64 bit.

Loại IntPtr có thể được sử dụng bởi các ngôn ngữ hỗ trợ con trỏ và như một phương tiện phổ biến để tham chiếu dữ liệu giữa các ngôn ngữ làm và không hỗ trợ con trỏ.

Các đối tượng IntPtr cũng có thể được sử dụng để giữ tay cầm. Ví dụ, các thể hiện của IntPtr được sử dụng rộng rãi trong lớp System.IO.FileStream để giữ các tệp xử lý.

Loại IntPtr tuân thủ CLS, trong khi loại UIntPtr thì không. Chỉ loại IntPtr được sử dụng trong thời gian chạy ngôn ngữ chung. Loại UIntPtr được cung cấp chủ yếu để duy trì tính đối xứng kiến ​​trúc với loại IntPtr.

http://msdn.microsoft.com/en-us/l Library / system.intptr (VS.71) .aspx


5

Vâng, đây là trang MSDN liên quan đến IntPtr.

Dòng đầu tiên ghi:

Một loại nền tảng cụ thể được sử dụng để đại diện cho một con trỏ hoặc một tay cầm.

Đối với những gì một con trỏ hoặc xử lý là trang đi vào trạng thái:

Loại IntPtr có thể được sử dụng bởi các ngôn ngữ hỗ trợ con trỏ và như một phương tiện phổ biến để tham chiếu dữ liệu giữa các ngôn ngữ làm và không hỗ trợ con trỏ.

Các đối tượng IntPtr cũng có thể được sử dụng để giữ tay cầm. Ví dụ, các thể hiện của IntPtr được sử dụng rộng rãi trong lớp System.IO.FileStream để giữ các tệp xử lý.

Một con trỏ là một tham chiếu đến một vùng bộ nhớ chứa một số dữ liệu mà bạn quan tâm.

Một điều khiển có thể là một định danh cho một đối tượng và được truyền giữa các phương thức / lớp khi cả hai bên cần truy cập vào đối tượng đó.


2

An IntPtrlà một loại giá trị chủ yếu được sử dụng để giữ địa chỉ bộ nhớ hoặc tay cầm. Một con trỏ là một địa chỉ bộ nhớ. Một con trỏ có thể được gõ (ví dụ int*) hoặc tháo ra (ví dụ void*). Một của Windows xử lý là một giá trị mà thường là cùng kích thước (hoặc nhỏ hơn) so với một địa chỉ bộ nhớ và đại diện cho một tài nguyên hệ thống (giống như một tập tin hoặc cửa sổ).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.