Untuk apa uintptr_t
dan untuk apa itu digunakan?
Untuk apa uintptr_t
dan untuk apa itu digunakan?
Jawaban:
uintptr_t
adalah tipe integer yang tidak ditandatangani yang mampu menyimpan data pointer. Yang biasanya berarti ukurannya sama dengan pointer.
Secara opsional didefinisikan dalam C ++ 11 dan standar selanjutnya.
Alasan umum untuk menginginkan tipe integer yang dapat menampung tipe pointer arsitektur adalah untuk melakukan operasi spesifik integer pada pointer, atau untuk mengaburkan tipe pointer dengan menyediakannya sebagai "handle" integer.
Sunting: Perhatikan bahwa Steve Jessop memiliki beberapa detail tambahan yang sangat menarik (yang tidak akan saya curi) di jawaban lain di sini untuk Anda yang bertipe jagoan :)
size_t
hanya perlu cukup untuk menampung ukuran objek terbesar, dan bisa lebih kecil dari pointer. Ini diharapkan pada arsitektur tersegmentasi seperti 8086 (16 bit size_t
, tapi 32 bit void*
)
ptrdiff_t
. uintptr_t
tidak dimaksudkan untuk itu.
unsigned int
biasanya tidak cukup besar. Tapi itu mungkin cukup besar. Jenis ini ada khusus untuk menghapus semua "asumsi" .
Hal pertama, pada saat pertanyaan itu diajukan, uintptr_t
tidak ada di C ++. Ada dalam C99, in <stdint.h>
, sebagai tipe opsional. Banyak kompiler C ++ 03 menyediakan file itu. Itu juga di C ++ 11, di, di <cstdint>
mana lagi itu opsional, dan yang merujuk ke C99 untuk definisi.
Di C99, ini didefinisikan sebagai "tipe integer yang tidak ditandai dengan properti bahwa setiap pointer yang valid ke void dapat dikonversi ke tipe ini, kemudian dikonversi kembali ke pointer ke void, dan hasilnya akan dibandingkan dengan pointer asli".
Anggap ini berarti apa yang dikatakannya. Itu tidak mengatakan apa-apa tentang ukuran.
uintptr_t
mungkin ukurannya sama dengan a void*
. Mungkin lebih besar. Bisa dibayangkan bisa lebih kecil, meskipun pendekatan implementasi C ++ buruk. Misalnya pada beberapa platform hipotetis di mana void*
32 bit, tetapi hanya 24 bit ruang alamat virtual yang digunakan, Anda bisa memiliki 24-bit uintptr_t
yang memenuhi persyaratan. Saya tidak tahu mengapa implementasi akan melakukan itu, tetapi standar mengizinkannya.
void*
. Ini memengaruhi kemungkinan arah di masa mendatang, terutama, jika Anda mungkin ingin mengubah untuk menggunakan sesuatu yang benar-benar hanya merupakan pegangan bilangan bulat, bukan penunjuk yang dikonversi sama sekali.
typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;
. Sebaliknya: callback.dataPtr = (void*)val
. Di sisi lain, Anda tentu saja void*
harus dan harus mengembalikannya int
.
Ini adalah tipe integer yang tidak ditandai persis ukuran pointer. Setiap kali Anda perlu melakukan sesuatu yang tidak biasa dengan pointer - seperti misalnya membalikkan semua bit (jangan tanya mengapa) Anda melemparkannya ke uintptr_t
dan memanipulasinya sebagai bilangan bulat biasa, lalu balas kembali.
void*
nilai pointer ke uintptr_t
dan kembali lagi menghasilkan void*
nilai yang sebanding dengan pointer asli. uintptr_t
biasanya ukurannya sama dengan void*
, tetapi itu tidak dijamin, juga tidak ada jaminan bahwa bit dari nilai yang dikonversi memiliki arti tertentu. Dan tidak ada jaminan bahwa itu dapat menyimpan nilai pointer-ke-fungsi yang dikonversi tanpa kehilangan informasi. Akhirnya, itu tidak dijamin ada.
Sudah ada banyak jawaban bagus untuk bagian "apa itu tipe data uintptr_t". Saya akan mencoba menjawab "untuk apa itu digunakan?" bagian dalam posting ini.
Terutama untuk operasi bitwise pada pointer. Ingat bahwa dalam C ++ seseorang tidak dapat melakukan operasi bitwise pada pointer. Untuk alasan, lihat Mengapa Anda tidak bisa melakukan operasi bitwise pada pointer di C, dan apakah ada cara untuk mengatasi ini?
Jadi, untuk melakukan operasi bitwise pada pointer, seseorang harus melemparkan pointer untuk mengetikkan unitpr_t dan kemudian melakukan operasi bitwise.
Berikut adalah contoh dari fungsi yang baru saja saya tulis untuk melakukan bitwise eksklusif atau dari 2 pointer untuk disimpan dalam daftar tertaut XOR sehingga kita dapat melintasi kedua arah seperti daftar yang tertaut ganda tetapi tanpa penalti menyimpan 2 pointer di setiap node .
template <typename T>
T* xor_ptrs(T* t1, T* t2)
{
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
}
Menjalankan risiko mendapatkan lencana Necromancer lain, saya ingin menambahkan satu penggunaan yang sangat baik untuk uintptr_t (atau bahkan intptr_t) dan itu adalah penulisan kode tertanam yang dapat diuji. Saya menulis sebagian besar kode tertanam yang ditargetkan pada berbagai lengan dan prosesor saat ini tensilica. Ini memiliki berbagai lebar bus asli dan tensilica sebenarnya adalah arsitektur Harvard dengan kode dan data bus terpisah yang dapat berbeda lebar. Saya menggunakan gaya pengembangan yang digerakkan oleh tes untuk sebagian besar kode saya yang berarti saya melakukan tes unit untuk semua unit kode yang saya tulis. Pengujian unit pada perangkat keras target yang sebenarnya adalah sebuah kerumitan jadi saya biasanya menulis semuanya pada PC berbasis Intel baik di Windows atau Linux menggunakan Ceedling dan GCC. Yang sedang berkata, banyak kode tertanam melibatkan sedikit twiddling dan manipulasi alamat. Sebagian besar mesin Intel saya 64 bit. Jadi jika Anda akan menguji kode manipulasi alamat Anda memerlukan objek umum untuk melakukan matematika. Jadi, uintptr_t memberi Anda cara mandiri untuk debugging kode Anda sebelum Anda mencoba menggunakan perangkat keras target. Masalah lain adalah untuk beberapa mesin atau bahkan model memori pada beberapa kompiler, fungsi pointer dan pointer data memiliki lebar yang berbeda. Pada mesin-mesin itu, kompiler bahkan mungkin tidak mengizinkan casting di antara dua kelas, tetapi uintptr_t harus bisa menahan keduanya.