কী uintptr_t
এবং এটি কী জন্য ব্যবহার করা যেতে পারে?
std::uintptr_t
এবং std::intptr_t
একটি সি ++ 11 .চ্ছিক ।
কী uintptr_t
এবং এটি কী জন্য ব্যবহার করা যেতে পারে?
std::uintptr_t
এবং std::intptr_t
একটি সি ++ 11 .চ্ছিক ।
উত্তর:
uintptr_t
একটি স্বাক্ষরবিহীন পূর্ণসংখ্যা টাইপ যা ডেটা পয়েন্টার সংরক্ষণের জন্য সক্ষম। যার সাধারণত অর্থ এটি পয়েন্টার হিসাবে একই আকার।
এটি সি ++ 11 এবং পরবর্তী মানেরগুলিতে optionচ্ছিকভাবে সংজ্ঞায়িত করা হয়েছে।
একটি আর্কিটেকচারের পয়েন্টার টাইপ ধরে রাখতে পারে এমন একটি পূর্ণসংখ্যার প্রকারের সাধারণ কারণ হ'ল একটি পয়েন্টারে পূর্ণসংখ্যা-নির্দিষ্ট ক্রিয়াকলাপ সম্পাদন করা, বা কোনও পূর্ণসংখ্যার "হ্যান্ডেল" হিসাবে সরবরাহ করে পয়েন্টারটির প্রকারটিকে অস্পষ্ট করে তোলা।
সম্পাদনা করুন: নোট করুন যে স্টিভ জেসপের কাছে আপনার পেডেন্টিক প্রকারের জন্য এখানে আরও একটি উত্তরে কিছু আকর্ষণীয় অতিরিক্ত বিশদ রয়েছে (যা আমি চুরি করব না) :)
size_t
বৃহত্তমতম অবজেক্টের আকার ধারণ করার জন্য কেবল পর্যাপ্ত পরিমাণের প্রয়োজন এবং এটি কোনও পয়েন্টারের চেয়ে ছোট হতে পারে। এটি 8086 (16 বিট size_t
, তবে 32 বিট void*
) এর মতো
ptrdiff_t
। uintptr_t
এর জন্য নয়
unsigned int
সাধারণত যথেষ্ট পরিমাণে বড় হয় না। তবে এটি যথেষ্ট বড় হতে পারে। এই ধরণেরটি সমস্ত "ধরে নেওয়া" মুছে ফেলার জন্য বিশেষভাবে বিদ্যমান ।
প্রথম জিনিস, যখন প্রশ্নটি জিজ্ঞাসা করা হয়েছিল, uintptr_t
তখন সি ++ তে ছিল না। এটি সি 99 এ <stdint.h>
, একটি alচ্ছিক প্রকার হিসাবে। অনেক সি ++ 03 সংকলক ফাইলটি সরবরাহ করে। এটি সি ++ এও রয়েছে <cstdint>
, যেখানে আবার এটি alচ্ছিক এবং এটি সংজ্ঞাটির জন্য C99 কে বোঝায়।
C99-তে, এটি এমন সংজ্ঞা হিসাবে সংজ্ঞা দেওয়া হয় যে "সম্পত্তিটির সাথে স্বাক্ষরবিহীন পূর্ণসংখ্যা টাইপ যা কোনও বৈধ পয়েন্টারকে শূন্যে রূপান্তর করতে পারে, তারপরে আবার পয়েন্টারটিকে শূন্যে রূপান্তরিত করা যায় এবং ফলাফলটি মূল পয়েন্টারের সমান তুলনা করবে"।
এটি যা বলে তা বোঝাতে এটি নিন। এটি আকার সম্পর্কে কিছু বলে না।
uintptr_t
একটি হিসাবে একই আকার হতে পারে void*
। এটি আরও বড় হতে পারে। এটি সম্ভবত ছোট হতে পারে, যদিও এই জাতীয় সি ++ বাস্তবায়ন বিকৃত হয়। উদাহরণস্বরূপ এমন কিছু অনুমানের প্ল্যাটফর্ম যেখানে 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 ডেটা টাইপ কী" অংশটির ইতিমধ্যে অনেকগুলি ভাল উত্তর রয়েছে। আমি "এটি কীসের জন্য ব্যবহার করা যেতে পারে?" সম্বোধনের চেষ্টা করব? এই পোস্টে অংশ।
প্রাথমিকভাবে পয়েন্টারে বিটওয়াইজ অপারেশনের জন্য। মনে রাখবেন যে সি ++ তে কেউ পয়েন্টারে বিটওয়াইজ অপারেশন করতে পারে না। কারণগুলির জন্য দেখুন কেন আপনি সি এর পয়েন্টারে বিটওয়াইজ অপারেশন করতে পারবেন না এবং এর চারপাশে কোনও উপায় আছে?
সুতরাং পয়েন্টারগুলিতে বিটওয়াইজ অপারেশন করার জন্য পয়েন্টারগুলিকে ইউনিট_প্রাইটি টাইপ করতে হবে এবং তারপরে বিটওয়াইড অপারেশন করা উচিত।
আমি এখানে একটি ক্রিয়াকলাপের উদাহরণ যা আমি কেবল বিটওয়াইজ এক্সক্লুসিভ করার জন্য লিখেছি বা একটি এক্সওআর লিঙ্কযুক্ত তালিকায় 2 পয়েন্টার সংরক্ষণ করার জন্য যাতে আমরা উভয় দিকটি দ্বিগুণ সংযুক্ত তালিকার মতো অতিক্রম করতে পারি তবে প্রতিটি নোডে 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));
}
আরেকটি নেক্রোম্যান্সার ব্যাজ পাওয়ার ঝুঁকি নিয়ে, আমি uintptr_t (অথবা এমনকি ইন্ট্রিটার_ টি) এর জন্য একটি খুব ভাল ব্যবহার যুক্ত করতে চাই এবং এটি টেস্টেবল এম্বেডড কোড লিখছে। আমি বেশিরভাগ এম্বেড কোড বিভিন্ন বাহু এবং বর্তমানে টেনসিলিকা প্রসেসরে লক্ষ্য করে লিখি। এর বিভিন্ন নেটিভ বাসের প্রস্থ রয়েছে এবং টেনসিলিকা আসলে একটি হার্ভার্ড আর্কিটেকচার যা পৃথক কোড এবং ডেটা বাস যা বিভিন্ন প্রস্থ হতে পারে। আমি আমার কোডের বেশিরভাগের জন্য একটি পরীক্ষা চালিত বিকাশ শৈলী ব্যবহার করি যার অর্থ আমি যে সমস্ত কোড ইউনিট লিখি তার ইউনিট পরীক্ষা করি tests প্রকৃত টার্গেট হার্ডওয়্যারের উপর ইউনিট পরীক্ষা করা একটি ঝামেলা তাই আমি সাধারণত উইন্ডোজ বা লিনাক্সে সিডলিং এবং জিসিসি ব্যবহার করে ইন্টেল ভিত্তিক পিসিতে সবকিছু লিখি। বলা হচ্ছে, এম্বেড করা প্রচুর কোডে বিট টুইডলিং এবং অ্যাড্রেস ম্যানিপুলেশনগুলি জড়িত। আমার বেশিরভাগ ইন্টেল মেশিন 64 বিট। সুতরাং আপনি যদি ঠিকানা ম্যানিপুলেশন কোডটি পরীক্ষা করতে যাচ্ছেন আপনার গাণিতিক করার জন্য আপনার একটি সাধারণ বস্তু প্রয়োজন। সুতরাং uintptr_t আপনি হার্ডওয়ারকে লক্ষ্যবস্তু করার জন্য মোতায়েন করার আগে আপনার কোডটি ডিবাগ করার একটি মেশিনকে স্বাধীন উপায় দেয়। আরেকটি সমস্যা হ'ল কিছু মেশিন বা এমনকি কিছু সংকলকগুলির মেমরি মডেলগুলির জন্য, ফাংশন পয়েন্টার এবং ডেটা পয়েন্টারগুলি পৃথক প্রস্থ। এই মেশিনগুলিতে সংকলক এমনকি দুটি শ্রেণীর মধ্যে কাস্টিংও মঞ্জুর করতে পারে না, তবে uintptr_t উভয়ই রাখতে সক্ষম হবে।