Nedir uintptr_t
ve ne için kullanılabilir?
std::uintptr_t
ve std::intptr_t
isteğe bağlı bir C ++ 11.
Nedir uintptr_t
ve ne için kullanılabilir?
std::uintptr_t
ve std::intptr_t
isteğe bağlı bir C ++ 11.
Yanıtlar:
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 :)
size_t
sadece 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
ptrdiff_t
. uintptr_t
bunun için değil.
unsigned int
genellikle 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 .
İlk şey, soru sorulduğu uintptr_t
sı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_t
ile 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.
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.
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
.
İş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_t
ve normal bir tamsayı numarası olarak manipüle ettiğiniz gibi geri çevirin.
void*
işaretçi değerini uintptr_t
tekrar ve geri dönüştürmenin void*
orijinal işaretçiye eşit bir değer vermesidir. uintptr_t
genellikle 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.
"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));
}
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.