มันคืออะไรuintptr_t
และใช้ทำอะไรได้บ้าง?
มันคืออะไรuintptr_t
และใช้ทำอะไรได้บ้าง?
คำตอบ:
uintptr_t
เป็นชนิดจำนวนเต็มที่ไม่ได้ลงนามที่สามารถเก็บตัวชี้ข้อมูลได้ ซึ่งโดยทั่วไปหมายความว่ามีขนาดเท่ากับตัวชี้
มันถูกกำหนดเป็นทางเลือกใน C ++ 11 และมาตรฐานในภายหลัง
เหตุผลทั่วไปในการต้องการประเภทจำนวนเต็มที่สามารถเก็บประเภทตัวชี้ของสถาปัตยกรรมคือการดำเนินการเฉพาะจำนวนเต็มบนตัวชี้หรือปิดบังประเภทของตัวชี้โดยให้เป็น "จัดการ" จำนวนเต็ม
แก้ไข: โปรดทราบว่า Steve Jessop มีรายละเอียดเพิ่มเติมที่น่าสนใจ (ซึ่งฉันจะไม่ขโมย) ในคำตอบอื่นที่นี่สำหรับคุณประเภทที่คลั่งไคล้ :)
size_t
จะต้องมีเพียงพอที่จะเก็บขนาดที่ใหญ่ที่สุดของวัตถุและอาจมีขนาดเล็กกว่าตัวชี้ นี้คาดว่าจะมีสถาปัตยกรรมแบ่งเช่น 8086 (16 บิตsize_t
แต่ 32 บิตvoid*
)
ptrdiff_t
สำหรับตัวแทนของความแตกต่างระหว่างสองตัวชี้ที่คุณมี uintptr_t
ไม่ได้มีไว้สำหรับสิ่งนั้น
unsigned int
มักจะไม่ใหญ่พอ แต่มันอาจมีขนาดใหญ่พอ ประเภทนี้มีอยู่โดยเฉพาะเพื่อลบ"สมมติ"ทั้งหมด
สิ่งแรกเวลาที่ถามคำถามuintptr_t
ไม่ได้อยู่ใน C ++ มันอยู่ใน C99 ใน<stdint.h>
เป็นอุปกรณ์เสริม คอมไพเลอร์ C ++ 03 จำนวนมากให้ไฟล์นั้น นอกจากนี้ยังอยู่ใน C ++ 11 <cstdint>
ที่ซึ่งเป็นตัวเลือกอีกครั้งและหมายถึง C99 สำหรับคำจำกัดความ
ใน C99 มันถูกกำหนดเป็น "ชนิดจำนวนเต็มที่ไม่ได้ลงชื่อพร้อมคุณสมบัติที่ตัวชี้ที่ถูกต้องใด ๆ เป็นโมฆะสามารถแปลงเป็นประเภทนี้จากนั้นแปลงกลับเป็นตัวชี้เป็นโมฆะและผลลัพธ์จะเปรียบเทียบเท่ากับตัวชี้ดั้งเดิม"
ใช้สิ่งนี้เพื่อหมายถึงสิ่งที่พูด มันไม่ได้พูดอะไรเกี่ยวกับขนาด
uintptr_t
void*
อาจจะมีขนาดเดียวกับ มันอาจใหญ่กว่านี้ มันอาจจะมีขนาดเล็กลงแม้ว่าการใช้งาน C ++ เช่นนั้นจะผิดเพี้ยนไป ตัวอย่างเช่นบนแพลตฟอร์มสมมุติบางตัวที่void*
มี 32 บิต แต่ใช้พื้นที่ที่อยู่เสมือนเพียง 24 บิตคุณอาจมี 24 บิตuintptr_t
ที่ตรงกับความต้องการ ฉันไม่รู้ว่าทำไมการนำไปใช้จะทำเช่นนั้น แต่มาตรฐานอนุญาต
void*
ที่แตกต่างจากการใช้ มันมีผลต่อทิศทางในอนาคตที่เป็นไปได้โดยเฉพาะอย่างยิ่งถ้าคุณอาจต้องการที่จะเปลี่ยนการใช้สิ่งที่เป็นเพียงการจัดการจำนวนเต็มไม่ใช่ตัวชี้ที่แปลงแล้ว
typedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;
ช่วยให้คุณประหยัดการกดแป้นพิมพ์ แทน: callback.dataPtr = (void*)val
. ในอีกด้านหนึ่งคุณแน่นอนจะได้รับและมีการโยนมันกลับไปvoid*
int
มันเป็นจำนวนเต็มชนิดที่ไม่ได้ลงนามตรงขนาดของตัวชี้ เมื่อใดก็ตามที่คุณต้องทำสิ่งผิดปกติด้วยตัวชี้ - เช่นกลับด้านบิตทั้งหมด (อย่าถามว่าทำไม) คุณโยนมันลงไปuintptr_t
และจัดการมันให้เป็นจำนวนเต็มปกติจากนั้นก็โยนกลับ
void*
ค่าตัวชี้ไปเป็นuintptr_t
กลับมาอีกครั้งจะให้void*
ค่าที่เปรียบเทียบเท่ากับตัวชี้ดั้งเดิม uintptr_t
มักจะมีขนาดเท่าvoid*
กัน แต่ไม่รับประกันและไม่มีการรับประกันใด ๆ ว่าบิตของค่าที่แปลงมีความหมายเฉพาะใด ๆ และไม่รับประกันว่าจะสามารถเก็บค่าตัวชี้ไปยังฟังก์ชันที่แปลงแล้วโดยไม่สูญเสียข้อมูล ในที่สุดก็ไม่รับประกันว่าจะมีอยู่
มีคำตอบที่ดีมากมายในส่วน "สิ่งที่เป็น uintptr_t ชนิดข้อมูล" ฉันจะพยายามพูดถึง "สิ่งที่สามารถใช้เพื่ออะไร" มีส่วนร่วมในโพสต์นี้
เป็นหลักสำหรับการดำเนินงานระดับบิตบนพอยน์เตอร์ โปรดจำไว้ว่าใน C ++ จะไม่สามารถทำการดำเนินการระดับบิตบนพอยน์เตอร์ได้ ด้วยเหตุผลดูที่ทำไมคุณไม่สามารถทำการดำเนินการระดับบิตบนตัวชี้ใน C และมีวิธีแก้ไขปัญหานี้?
ดังนั้นเพื่อที่จะทำการดำเนินการระดับบิตบนพอยน์เตอร์คุณจะต้องส่งพอยน์เตอร์เพื่อพิมพ์ unitpr_t แล้วจึงทำการดำเนินการระดับบิต
นี่คือตัวอย่างของฟังก์ชั่นที่ฉันเพิ่งเขียนให้ทำ bitwise exclusive หรือ 2 pointers เพื่อเก็บไว้ใน XOR linked list เพื่อให้เราสามารถท่องไปในทั้งสองทิศทางเหมือนกับรายการที่เชื่อมโยงทวีคูณ แต่ไม่มีโทษของการเก็บ 2 พอยน์เตอร์ในแต่ละโหนด .
template <typename T>
T* xor_ptrs(T* t1, T* t2)
{
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
}
การเสี่ยงต่อการได้รับตรา Necromancer อีกครั้งฉันต้องการเพิ่มการใช้งานที่ดีมากสำหรับ uintptr_t (หรือแม้กระทั่ง intptr_t) และนั่นเป็นการเขียนโค้ดแบบฝังที่สามารถทดสอบได้ ฉันเขียนโค้ดที่ฝังตัวส่วนใหญ่มุ่งไปที่แขนหลายแขนงและตัวประมวลผลแบบดึงในปัจจุบัน สิ่งเหล่านี้มีความกว้างของบัสเนทีฟต่าง ๆ และแรงดึงเป็นสถาปัตยกรรมฮาร์วาร์ดที่มีโค้ดแยกต่างหากและบัสข้อมูลที่มีความกว้างต่างกัน ฉันใช้รูปแบบการพัฒนาที่ขับเคลื่อนด้วยการทดสอบสำหรับรหัสส่วนใหญ่ของฉันซึ่งหมายความว่าฉันทำการทดสอบหน่วยสำหรับหน่วยรหัสทั้งหมดที่ฉันเขียน การทดสอบหน่วยบนฮาร์ดแวร์เป้าหมายที่เกิดขึ้นจริงเป็นเรื่องยุ่งยากดังนั้นโดยทั่วไปฉันเขียนทุกอย่างบนพีซีที่ใช้ Intel ทั้งใน Windows หรือ Linux โดยใช้ Ceedling และ GCC ที่ถูกกล่าวว่ารหัสฝังตัวจำนวนมากที่เกี่ยวข้องกับการ twiddling บิตและการจัดการที่อยู่ เครื่อง Intel ส่วนใหญ่ของฉันคือ 64 บิต ดังนั้นหากคุณจะทดสอบรหัสการจัดการที่อยู่คุณต้องมีวัตถุทั่วไปที่จะทำคณิตศาสตร์ ดังนั้น uintptr_t จะให้วิธีที่เป็นอิสระในการดีบักรหัสของคุณกับเครื่องก่อนที่คุณจะลองปรับใช้กับฮาร์ดแวร์เป้าหมาย ปัญหาอีกประการหนึ่งสำหรับเครื่องบางรุ่นหรือแม้แต่รุ่นหน่วยความจำในคอมไพเลอร์บางตัวชี้ฟังก์ชั่นและพอยน์เตอร์ข้อมูลมีความกว้างต่างกัน บนเครื่องเหล่านั้นคอมไพเลอร์อาจไม่อนุญาตให้ทำการแคสต์ระหว่างสองคลาส แต่ uintptr_t ควรจะสามารถเก็บไว้ได้เช่นกัน