IntPtr tam olarak nedir?


171

IntelliSense'i kullanarak ve başkalarının kodlarına bakarak bu IntPtrtipte karşılaştım; her kullanılması gerektiğinde, çoğu işlevi işe koydum nullveya IntPtr.Zerobuldum. Tam olarak nedir ve ne zaman / neden kullanılır?

Yanıtlar:


158

"Yerel (platforma özgü) boyutta bir tam sayı." Dahili olarak temsil edilir, void*ancak bir tamsayı olarak gösterilir. Yönetilmeyen bir işaretçiyi saklamanız gerektiğinde ve unsafekod kullanmak istemediğinizde kullanabilirsiniz . IntPtr.Zeroetkin NULL(boş gösterici).


53
İşaretçi, bellekteki bir adrese işaret eden bir şeydir. Yönetilen dillerde referanslarınız var (adres hareket edebilir), yönetilmeyen dillerde işaretçiler var (adres sabittir)
Colin Mackay

93
Genel olarak (programlama dilleri arasında), bir işaretçi bellekteki fiziksel bir konumu temsil eden bir sayıdır. Bir boş işaretçi olduğu noktalar 0 (neredeyse her zaman) biridir ve yaygın "bir şey göstermiyorsa" olarak kabul edilmektedir. Sistemlerin farklı miktarlarda desteklenen belleği olduğundan, bu sayıyı tutmak için her zaman aynı sayıda bayt almaz, bu nedenle herhangi bir belirli sistemde bir işaretçi tutabilecek bir "yerel boyut tamsayı" diyoruz.
Sam Harwell

5
@ 280Z28 için bu yorum için +1, bu şimdiye kadar gördüğüm işaretçilerin en özlü açıklaması.
BlueRaja - Danny Pflughoeft

9
IntPtr olarak adlandırılır, çünkü yönetilmeyen yerel kod olan C / C ++ ile kullanmak için, intptr_t analog türünü kullanmanız gerekir. C # 'ın IntPtr tam olarak C / C ++' ın intptr_t ile eşleşir. Ve muhtemelen intptr_t olarak uygulanır. C / C ++ 'da, intptr_t türünün void * türüyle aynı boyutta olması garanti edilir.
Петър Петров

2
@Trap "İşaretçiyi veya tanıtıcıyı temsil etmek için kullanılan platforma özgü bir tür." "Platforma özgü bir tam sayı" değil, "bir işaretçiyi veya tanıtıcıyı temsil etmek için platforma özgü bir yol" değildir. IntPtrmükemmel bir anlam ifade eder, çünkü bir tamsayıdır (matematiksel tamsayıda olduğu gibi) ve bir işaretçi (işaretçide olduğu gibi). Bölümün Intint türüyle ilgisi yoktur - bu bir kavramdır, belirli bir tür değildir. Adil olmakla birlikte, CLI spesifikasyonunun bu konuda söylediği tek şey, bunun bir "Tamsayı, yerel boyut" olduğudur. Oh well :)
Luaan

69

Bellek adresini yerel veya güvenli olmayan kodda kullanıldığı şekilde depolayacak kadar büyük ancak güvenli yönetilen kodda doğrudan bellek adresi olarak kullanılamayan bir değer türüdür.

IntPtr.SizeSırasıyla 4 veya 8 bayt olacağından, 32 bit veya 64 bit işlemde çalışıp çalışmadığınızı öğrenmek için kullanabilirsiniz .


16
İşlem için adres alanının büyüklüğünü tespit etme konusunda iyi bir nokta.
Noldorin

@Noldorin Doğru, ancak güvenilir olması gerekmez. Geçmişte, çok sayıda işaretçi türüne sahip çok sayıda mimari vardı ve Windows'ta, IntPtrmimariden bağımsız olarak 32 bitlik tutamaçları temsil etmek için de kullanılıyordu (yine Sizede bu durumda 8 diyor). CLI spesifikasyonu sadece bunun "yerel boyutta" bir tamsayı olduğuna dikkat çeker, ancak bu pek bir şey söylemez.
Luaan

@Luaan cevabımda hiçbir şeyi gerçekten değiştirmiyor mu? IntPtr, bir bellek adresini tutacak kadar büyük bir değer olarak adlandırılır (ve CLR kaynağı boyunca kullanılır). Elbette daha küçük değerleri tutabilir. Bazı mimarilerin çoklu işaretçi türleri vardır, ancak kümenin en büyüğü olanları olmalıdır.
Daniel Earwicker

@DanielEarwicker Eh, bildiğim kadarıyla, herhangi bir geçerli .NET uygulaması ile ilgili bir sorun değil. Bununla birlikte, (tarihsel) sorun sadece boyutla ilgili değildir - çeşitli işaretçiler tamamen uyumsuz olabilir. Bugüne daha yakın bir örnekte, "yerel işaretçi boyutu" hala 32 bit olsa da, PAE 64 bit adresleri kullanacaktır. "32-bit sistemi gerçekten ne anlama geliyor?" Argümanına kadar uzanıyor. Şimdi 256 bit ve 512 bit sayısal kayıtlarımız var, ancak yine de 64 bit olarak adlandırıyoruz. Eğer rağmen edemez aslında 64 bit "işaretçiler" ile fiziksel bellek 64-bit adres. Bu bir karmaşa.
Luaan

1
Bazıları karmaşık, ancak IntPtr hala "bir bellek adresini saklamak için yeterince büyük bir değer türüdür". Örneklerinizden birini almak, en büyük donanım kaydı kadar büyük değildir. Bunun için değil. Bir bellek adresini temsil edecek kadar büyük. Sonra böyle şeyler var: stackoverflow.com/questions/12006854/… bellek adresinden başka bir şey için kullanılan "işaretçi" kelimesi var - bu yüzden özellikle "bellek adresi" dedim.
Daniel Earwicker

48

İşte bir örnek:

Yüksek hızlı bir kamerayla arayüz oluşturan bir C # programı yazıyorum. Kameranın görüntüleri otomatik olarak alıp otomatik olarak bilgisayarın belleğine yükleyen kendi sürücüsü var.

Bu yüzden çalışmak için programıma en son görüntüyü getirmeye hazır olduğumda, kamera sürücüsü bana görüntünün ZATEN fiziksel bellekte saklandığı yere bir IntPtr sağlar, bu yüzden başka bir şey yaratarak zaman / kaynak harcamak zorunda kalmam bellekte bulunan bir görüntüyü saklamak için bellek bloğu. IntPtr bana görüntünün zaten nerede olduğunu gösteriyor.


7
Yani IntPtr basit yönetilen kodda yönetilmeyen bir işaretçi (kamera sürücünüzde kullanılan gibi) kullanmanızı sağlar?
Callum Rogers

5
Evet. Bu durumda, büyük olasılıkla kamera sürücüsü kaputun altında yönetilmeyen sürücüler kullanıyor, ancak Yalnızca Yönetilen dünyasında düzgün çalışmak için IntPtr'e verilerle güvenli bir şekilde çalışmama izin veriyor.
bufferz

3
Öyleyse neden size bir akışı (bayt dizisi) geri vermiyor? Neden güvensiz veya değeri döndüremiyor?
Muffin Adam

35

Doğrudan yorumlama

Bir ıntptr bir bir tam sayıdır , bir aynı boyutta olan işaretçi .

İşaretçi türünü işaretçi olmayan bir türde saklamak için IntPtr kullanabilirsiniz. Bu özellik .NET'te önemlidir çünkü işaretçilerin kullanımı hataya açıktır ve bu nedenle çoğu bağlamda yasa dışıdır. İşaretçi değerinin "güvenli" bir veri türünde depolanmasına izin vererek, güvenli olmayan kod bölümleri arasında sıhhi tesisat daha güvenli üst düzey kodlarda, hatta doğrudan işaretçileri desteklemeyen bir .NET dilinde uygulanabilir.

IntPtr'in boyutu platforma özgüdür, ancak sistem otomatik olarak doğru boyutu kullanacağından bu ayrıntı nadiren dikkate alınmalıdır.

"IntPtr" adı kafa karıştırıcı - benzer bir şey Handledaha uygun olabilirdi. Benim ilk tahminim "IntPtr" bir tamsayı için bir işaretçi oldu . IntPtr MSDN belgelerine hiç isminin anlamı hakkında daha fazla fikir vermeden biraz şifreli ayrıntılı anlatır.

Alternatif bir bakış açısı

An IntPtr, iki sınırlamaya sahip bir göstericidir:

  1. Doğrudan kayıttan çıkarılamaz
  2. İşaret ettiği verilerin türünü bilmiyor.

Başka bir deyişle, an IntPtrtıpkı bir void*- gibidir, ancak temel işaretçi aritmetiği için kullanılabileceği (ancak olmaması gerektiği) ekstra özelliğiyle.

Bir referanstan vazgeçmek için IntPtr, onu gerçek bir işaretçiye (yalnızca "güvenli olmayan" bağlamlarda gerçekleştirilebilen bir işlem) ya da InteropServices.Marshalsınıf tarafından sağlananlar gibi yardımcı bir yordama iletebilirsiniz . MarshalSınıfın kullanılması, açık bir "güvensiz" bağlamda olmanızı gerektirmediği için güvenlik yanılsamasını verir. Ancak, işaretçiler kullanmanın doğasında olan çökme riskini ortadan kaldırmaz.


2
"C" programlama dilinin C99 standardından "intptr" adı için bazı emsaller vardır. linux.die.net/man/3/intptr_t .
Brent Bradburn

17

İşaretçi nedir?

Tüm dillerde, bir işaretçi bir bellek adresini saklayan bir değişken türüdür ve sizden size işaret ettikleri adresi veya işaret ettikleri adresteki değeri söylemelerini isteyebilirsiniz .

Bir işaretçi bir tür kitap işareti olarak düşünülebilir. Bir kitaptaki bir sayfaya hızlı bir şekilde atlamak için kullanılmak yerine, bellek bloklarını takip etmek veya eşlemek için bir işaretçi kullanılır.

Programınızın belleğini tam olarak 65535 baytlık büyük bir dizi gibi düşünün.

İşaretçiler itaatkar bir şekilde işaret ediyor

İşaretçiler her biri bir bellek adresini hatırlar ve bu nedenle her biri bellekteki tek bir adresi gösterir.

Grup olarak, işaretçiler bellek adreslerini hatırlar ve hatırlar, her müziğinize uyarlar.

Onların kralı sizsiniz.

İşaretçiler C #

Özellikle C # 'da, bir işaretçi, 0 ile 65534 arasında bir bellek adresi depolayan bir tamsayı değişkenidir.

Ayrıca C # 'a özgü işaretçiler int türündedir ve bu nedenle imzalanmıştır.

Negatif olarak numaralandırılmış adresleri kullanamazsınız, 65534'ün üzerindeki bir adrese de erişemezsiniz. Bunu yapmaya yönelik herhangi bir girişim bir System.AccessViolationException özel durumu oluşturur.

MyPointer adlı bir işaretçi şöyle bildirilir:

int * MyPointer;

C # 'daki bir işaretçi bir int'tir, ancak C #' daki bellek adresleri 0'dan başlar ve 65534'e kadar uzanır.

Sivri şeyler ekstra özel dikkatle ele alınmalıdır

Sözcük güvensiz olduğu sizi korkutmak için tasarlanmış, ve çok iyi bir nedenden dolayı: İşaretçiler ekstra büyük dikkatle ele alınmalıdır vb sivri şeyler ve sivri şeyler mesela kılıç, balta, işaretçileri vardır.

İşaretçiler programcıya bir sistemin sıkı denetimini sağlar. Bu nedenle, yapılan hataların daha ciddi sonuçları olacaktır.

İşaretçileri kullanmak için, programınızın özelliklerinde güvenli olmayan kodun etkinleştirilmesi ve işaretçilerin yalnızca güvenli olmayan olarak işaretlenmiş yöntemlerde veya bloklarda kullanılması gerekir.

Güvenli olmayan bir blok örneği

unsafe
{
    // Place code carefully and responsibly here.

}

İşaretçiler nasıl kullanılır?

Değişkenler veya nesneler bildirildiğinde veya somutlaştırıldığında, bunlar bellekte saklanır.

  • * Sembol önekini kullanarak bir işaretçi bildirin.

int *MyPointer;

  • Bir değişkenin adresini almak için & sembol önekini kullanırsınız.

MyPointer = &MyVariable;

İşaretçiye bir adres atandığında, aşağıdakiler geçerlidir:

  • * Öneki olmadan int olarak gösterilen bellek adresine atıfta bulunun.

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

  • İşaret edilen bellek adresinde saklanan değeri almak için * öneki ile.

"MyPointer is pointing at " + *MyPointer;

İşaretçi bir bellek adresini tutan bir değişken olduğundan, bu bellek adresi bir işaretçi değişkeninde saklanabilir.

Dikkatli ve sorumlu bir şekilde kullanılan işaretçi örnekleri

    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.

    }

İşaretçinin türünün bir int olduğuna dikkat edin. Bunun nedeni, C # 'ın bellek adreslerini tamsayı (int) olarak yorumlamasıdır.

Neden uint yerine int?

Bunun iyi bir nedeni yok.

Neden işaretçiler kullanılır?

İşaretçiler çok eğlenceli. Bilgisayarın büyük bir kısmı bellek tarafından kontrol edildiğinde, işaretçiler bir programcıya programlarının belleğini daha fazla kontrol edebilmesini sağlar.

Bellek izleme.

Bellek bloklarını okumak ve değerlerin zaman içinde nasıl değiştiğine işaret etmek için işaretçiler kullanın.

Bu değerleri sorumlu bir şekilde değiştirin ve değişikliklerinizin bilgisayarınızı nasıl etkilediğini takip edin.


2
65534bir işaretçi aralığı olarak çok yanlış görünüyor. Bir referans vermelisiniz.
Brent Bradburn

1
Bunu oyladım çünkü işaretçileri açıklayan harika bir makale. Belirttiğiniz özelliklere bazı referanslar görmek istiyorum (yukarıda yorumlandığı gibi). Ancak; bu cevabın soru ile ilgisi yoktur. Soru şuyduSystem.IntPtr . Sonunda güncellenen yanıtı görmek için de ne System.IntPtrve bir # nasıl güvensiz işaretçiler ile ilgili açıklayan görmek istiyorum .
Michael Puckett II

7

MSDN bize şunları söylüyor:

IntPtr türü, boyutu platforma özgü bir tamsayı olacak şekilde tasarlanmıştır. Yani, bu tür bir örneğin 32 bit donanım ve işletim sistemlerinde 32 bit ve 64 bit donanım ve işletim sistemlerinde 64 bit olması beklenir.

IntPtr türü, işaretçileri destekleyen diller tarafından ve işaretçileri destekleyen ve desteklemeyen diller arasındaki verilere başvurmanın yaygın bir yolu olarak kullanılabilir.

IntPtr nesneleri tutamaçları tutmak için de kullanılabilir. Örneğin, IntPtr örnekleri System.IO.FileStream sınıfında dosya tanıtıcılarını tutmak için yaygın olarak kullanılır.

IntPtr türü CLS uyumludur, UIntPtr türü ise değildir. Ortak dil çalışma zamanında yalnızca IntPtr türü kullanılır. UIntPtr tipi çoğunlukla IntPtr tipi ile mimari simetriyi korumak için sağlanmıştır.

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


5

Bu, ilgilenen MSDN sayfasıIntPtr .

İlk satır şöyle:

Bir işaretçiyi veya tanıtıcıyı temsil etmek için kullanılan platforma özgü bir tür.

İşaretçinin veya tutamacın ne olduğuna ilişkin olarak sayfa şu şekilde devam eder:

IntPtr türü, işaretçileri destekleyen diller tarafından ve işaretçileri destekleyen ve desteklemeyen diller arasındaki verilere başvurmanın yaygın bir yolu olarak kullanılabilir.

IntPtr nesneleri tutamaçları tutmak için de kullanılabilir. Örneğin, IntPtr örnekleri System.IO.FileStream sınıfında dosya tanıtıcılarını tutmak için yaygın olarak kullanılır.

İşaretçi, ilgilendiğiniz bazı verileri tutan bir bellek alanına yapılan başvurudur.

Tanıtıcı bir nesne için tanımlayıcı olabilir ve her iki tarafın da o nesneye erişmesi gerektiğinde yöntemler / sınıflar arasında iletilir.


2

An IntPtr, öncelikle bellek adreslerini veya tanıtıcıları tutmak için kullanılan bir değer türüdür . Bir gösterici , bir bellek adresi. Bir işaretçi yazılabilir (örneğin int*) veya türsüz olabilir (örneğin void*). Bir tanıtıcı Windows genellikle bir bellek adresi ile aynı boyutta (veya daha küçük) ve (bir dosya ya da pencere gibi), bir sistem kaynağı temsil eden bir değerdir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.