Uintptr_t veri türü nedir


Yanıtlar:


199

uintptr_t, bir veri işaretçisini depolayabilen imzasız bir tamsayı türüdür. Bu genellikle bir işaretçi ile aynı boyutta olduğu anlamına gelir.

İsteğe bağlı olarak C ++ 11 ve sonraki standartlarda tanımlanır.

Mimarinin işaretçi türünü barındırabilecek bir tamsayı türü istemenin yaygın bir nedeni, bir işaretçi üzerinde tamsayıya özgü işlemler gerçekleştirmek veya bir işaretçi türünü bir tamsayı "tanıtıcı" olarak sağlayarak gizlemektir.

Düzenleme: Steve Jessop, sizin bilgiçlik türleri için burada başka bir cevap bazı çok ilginç ek detaylar (çalmayacağım) olduğunu unutmayın :)


53
Not size_tsadece ihtiyacı büyük nesnenin inci boyutu tutmak için yeterli olmak üzere, ve bir işaretçi daha küçük olabilir. Bu, 8086 (16 bit size_t, ancak 32 bit void*) gibi bölümlere ayrılmış mimarilerde beklenebilir
MSalters

3
iki işaretçi arasındaki farkı temsil ettiğiniz için, var ptrdiff_t. uintptr_tbunun için değil.
jalf

3
@jalf: Fark için, evet, ama mesafe için , imzasız bir tip istiyorsunuz.
Drew Dormann

uintptr_t tanımı görünüşe göre C ++ 11'de bile zorunlu değil (standart değil)! cplusplus.com/reference/cstdint (Steve Jessop cevabından ipucu aldım)
Antonio

2
@MarcusJ unsigned intgenellikle yeterince büyük değil. Ama yeterince büyük olabilir. Bu tür tüm "varsayımları" kaldırmak için özel olarak mevcuttur .
Drew Dormann

239

İlk şey, soru sorulduğu uintptr_tsırada, C ++ 'da değildi. <stdint.h>İsteğe bağlı bir tür olarak C99'dadır . Birçok C ++ 03 derleyicisi bu dosyayı sağlar. Ayrıca <cstdint>, yine isteğe bağlı olan ve tanım için C99'a atıfta bulunan C ++ 11'de .

C99'da, "geçersiz işaretli herhangi bir geçerli işaretçinin bu tipe dönüştürülebilmesi, daha sonra tekrar işaretleyiciye boşluğa dönüştürülebilmesi ve sonuç orijinal işaretçiye eşit olacak özellikte işaretsiz bir tamsayı türü olarak tanımlanır.

Ne dediğini anlamak için bunu al. Boyut hakkında bir şey söylemiyor.

uintptr_tile aynı boyutta olabilir void*. Daha büyük olabilir. Böyle bir C ++ uygulaması sapkın yaklaşsa da, muhtemelen daha küçük olabilir. Örneğin void*, 32 bit, ancak yalnızca 24 bit sanal adres alanı kullanılan bazı varsayımsal platformlarda uintptr_t, gereksinimi karşılayan bir 24 bitiniz olabilir. Bir uygulamanın neden bunu yapacağını bilmiyorum, ancak standart buna izin veriyor.


8
"<Stdint.h>" için teşekkürler. Uygulamam uintptr_t bildirimi nedeniyle derlenmedi. Ama yorumunuzu okuduğumda "#include <stdint.h>" ekliyorum ve şimdi çalışıyor. Teşekkürler!
JavaRunner

2
To hizalanmış bellek ayrılamadı örneğin diğer kullanımlar arasında,?
legends2k

4
Bir işaretçiyi int işaretine çevirmenin bir başka yaygın kullanım örneği, işaretçiyi gizleyen opak bir tutamaç oluşturmaktır. Bu, nesneyi kütüphaneye özel tutmak ve uygulamaların ona erişmesini engellemek istediğiniz API'lardan bir nesneye başvuru döndürmek için kullanışlıdır. Uygulama daha sonra nesne üzerinde herhangi bir işlem gerçekleştirmek için API kullanmak zorunda
Joel Cunningham

3
@JoelCunningham: işe yarıyor ama kullanmaktan gerçekten farklı değil void*. Gelecekteki olası yönleri etkiler, ancak özellikle dönüştürülmüş bir işaretçi değil, yalnızca tamsayı tutamacı olan bir şeyi kullanmak için değiştirmek isterseniz.
Steve Jessop

2
@CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Yaygın bir kullanım durumu, genel verilere boşluk * bekleyen bir API'ye yalnızca int iletmektir. Tuş vuruşlarını kaydeder typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;. Bunun yerine: callback.dataPtr = (void*)val. Diğer tarafta, elbette alıp void*geri almak zorundasınız int.
Francesco Dondi

19

İşaretçinin tam olarak işaretsiz bir tamsayı türüdür. Bir işaretçi ile olağandışı bir şey yapmanız gerektiğinde - örneğin, tüm bitleri ters çevirin (nedenini sormayın) uintptr_tve normal bir tamsayı numarası olarak manipüle ettiğiniz gibi geri çevirin.


6
Elbette bunu yapabilirsiniz, ancak bu elbette tanımsız bir davranış olacaktır. Ben o zaman uintptr_t için bir döküm sonucu ile yapabileceğiniz tek şey değişmeden geçmek ve geri döküm olduğuna inanıyorum - her şey UB.
sleske

Bitlerle oynamanız gereken zamanlar vardır ve normal olarak derleyici hataları oluşturur. Yaygın bir örnek, belirli video ve performans açısından kritik uygulamalar için 16 baytlık hizalanmış belleği zorlamaktır. stackoverflow.com/questions/227897/…
Cloud

3
@sleske bu doğru değil. Kendinden hizalı tiplere sahip makinelerde, bir işaretçinin en az iki önemli biti sıfır olacaktır (çünkü adresler 4 veya 8'in katlarıdır). Verileri sıkıştırmak için bunu kullanan programlar gördüm ..
saadtaame

3
@saadtaame: Bunun C standardına göre bunun UB olduğuna dikkat çektim . Bu, bazı sistemlerde tanımlanamayacağı anlamına gelmez - derleyiciler ve çalışma zamanları, standart C'de UB olan bir şey için belirli bir davranış tanımlamakta özgürdür. Dolayısıyla, çelişki yoktur :-).
sleske

2
Mutlaka bir işaretçinin boyutu olması gerekmez. Tüm standart garantiler, bir void*işaretçi değerini uintptr_ttekrar ve geri dönüştürmenin void*orijinal işaretçiye eşit bir değer vermesidir. uintptr_tgenellikle aynı boyuttadır void*, ancak bu garanti edilmez veya dönüştürülen değerin bitlerinin belirli bir anlamı olduğuna dair herhangi bir garanti yoktur. Ve bilgi kaybı olmadan dönüştürülmüş bir işaretçi-işlev değerini tutabileceğinin garantisi yoktur. Son olarak, varolduğu garanti edilmez.
Keith Thompson

15

"Uintptr_t veri türü nedir" bölümüne zaten çok iyi yanıtlar var. "Ne için kullanılabilir?" bu yazının bir parçası.

Öncelikle işaretçiler üzerinde bitsel işlemler için. C ++ 'da işaretçiler üzerinde bitsel işlemler yapamayacağınızı unutmayın. Nedenler için bkz . C işaretçisinde neden bitsel işlemler yapamıyorsunuz ve bunun bir yolu var mı?

Bu nedenle, işaretçiler üzerinde bitsel işlemler yapmak için, unitpr_t yazmak ve sonra bitsel işlemler yapmak için işaretçiler kullanmanız gerekir.

Burada sadece iki yönlü bağlantı yapmak için yazdığım bir fonksiyonun bir örneği ya da XOR bağlantılı listede saklamak için 2 işaretçi, böylece her iki yönde de iki bağlantılı bir liste gibi, ancak her bir düğümde 2 işaret saklamanın cezası olmadan geçebilmemiz için .

 template <typename T>
 T* xor_ptrs(T* t1, T* t2)
 {
     return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
  }

1
bit aritmetiği dışında, nesne sayımları yerine adreslere dayalı anlambiliminiz olması da hoş olur.
Alex

4

Başka bir Necromancer rozeti alma riskini çalıştırarak, uintptr_t (veya intptr_t) için çok iyi bir kullanım eklemek istiyorum ve bu test edilebilir gömülü kod yazıyor. Çoğunlukla çeşitli kol ve şu anda tensilica işlemcileri hedef alan gömülü kod yazıyorum. Bunlar çeşitli yerel veri yolu genişliğine sahiptir ve tensilica aslında farklı genişliklerde olabilen ayrı kod ve veri yollarına sahip bir Harvard mimarisidir. Kodumun çoğu için test odaklı geliştirme stili kullanıyorum, bu da yazdığım tüm kod birimleri için birim testleri yaptığım anlamına geliyor. Gerçek hedef donanım üzerinde birim testi bir güçlüktür, bu yüzden genellikle Intel tabanlı bir bilgisayarda her şeyi Ceedling ve GCC kullanarak Windows veya Linux'ta yazıyorum. Bununla birlikte, birçok gömülü kod biraz döndürme ve adres manipülasyonlarını içerir. Intel makinelerimin çoğu 64 bit. Bu yüzden adres değiştirme kodunu test edecekseniz, matematik yapmak için genelleştirilmiş bir nesneye ihtiyacınız vardır. Böylece uintptr_t, hedef donanıma konuşlandırmayı denemeden önce kodunuzda hata ayıklamak için makineden bağımsız bir yol sağlar. Başka bir sorun, bazı derleyiciler, işlev işaretçileri ve veri işaretleyicilerindeki bazı makineler veya hatta bellek modelleri için farklı genişliklerdir. Bu makinelerde derleyici iki sınıf arasında döküm yapılmasına bile izin vermeyebilir, ancak uintptr_t öğesinin ikisini de tutabilmesi gerekir.


Alakalı olup olmadığından emin değil misiniz? "Opak typedefs" i ​​denediniz mi? Vide: youtube.com/watch?v=jLdSjh8oqmE
shycha

@sleske Keşke bu C mevcuttu. Ama stdint.h sahip olmak hiç yoktan iyidir. (Ayrıca güçlü yazılan ancak çoğu hata ayıklayıcı onları herhangi bir şekilde bulmak için iyi bir iş yapmak enums diliyorum)
BD2357
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.