পুনরায় ব্যাখ্যা_কাস্ট কখন ব্যবহার করবেন?


459

আমি সামান্য এর প্রযোজ্যতা সঙ্গে গুলিয়ে ফেলা করছি reinterpret_castবনাম static_cast। আমি সাধারণ নিয়মগুলি যা পড়েছি তা থেকে স্থির কাস্ট ব্যবহার করা হয় যখন শব্দগুলি সংকলন করার সময় প্রকারের অর্থ ব্যাখ্যা করা যায় static। অন্তর্নিহিত ক্যাসেটগুলির জন্যও সি ++ সংকলক অভ্যন্তরীণভাবে ব্যবহার করে castালাই।

reinterpret_castগুলি দুটি পরিস্থিতিতে প্রযোজ্য:

  • পূর্ণসংখ্যার প্রকারকে পয়েন্টার ধরণের এবং বিপরীতে রূপান্তর করুন
  • একটি পয়েন্টার টাইপকে অন্যটিতে রূপান্তর করুন। আমি যে সাধারণ ধারণাটি পাই তা হ'ল অপ্রয়োজনীয় এবং এড়ানো উচিত।

যেখানে আমি একটু বিভ্রান্ত হচ্ছি সেগুলির একটি প্রয়োজন যা আমার প্রয়োজন, আমি সি থেকে সি ++ কল করছি এবং সি কোডটির সি ++ অবজেক্ট ধরে রাখা দরকার তাই মূলত এটি একটি থাকে void*void *ক্লাসের ধরণের মধ্যে রূপান্তর করতে কোন কাস্ট ব্যবহার করা উচিত ?

আমি উভয়ের ব্যবহার দেখেছি static_castএবং reinterpret_cast? যদিও আমি যা পড়ছি তা থেকে মনে staticহচ্ছে এটি সংকলনের সময় কাস্টটি ঘটতে পারে বলে ভাল? যদিও এটি reinterpret_castএক পয়েন্টার টাইপ থেকে অন্য পয়েন্টারে রূপান্তর করতে ব্যবহার করতে বলে ?


9
reinterpret_castরান সময় হয় না। তারা উভয় সংকলন-সময় বিবৃতি। En.cppreferences.com/w/cpp/language/reinter ব্যাখ্যা_cast থেকে : "স্ট্যাটিক_কাস্টের মতো নয়, তবে কনস্ট_কাস্টের মতো, পুনরায় ব্যাখ্যা_কাস্ট এক্সপ্রেশন কোনও সিপিইউ নির্দেশাবলীর সাথে সংকলন করে না pure অভিব্যক্তির (অবজেক্ট উপস্থাপনা) যেন নতুন টাইপ টাইপ করে। "
ক্রিস লুয়েংগো

@ হের্টোলিয়ার্ন, * * সি এবং * .সিপি ফাইল থেকে প্রাসঙ্গিক কোড টুকরো যুক্ত করা সম্ভব? আমি মনে করি এটি প্রশ্নের প্রকাশের উন্নতি করতে পারে।
ওরেনশালাম

উত্তর:


442

সি ++ স্ট্যান্ডার্ড নিম্নলিখিতগুলির গ্যারান্টি দেয়:

static_castvoid*ঠিকানাটি সংরক্ষণ করে এবং থেকে একটি পয়েন্টার যুক্ত করা । এটি, নীচে a, bএবং cসমস্ত একই ঠিকানার দিকে নির্দেশ করে:

int* a = new int();
void* b = static_cast<void*>(a);
int* c = static_cast<int*>(b);

reinterpret_castকেবলমাত্র গ্যারান্টি দেয় যে আপনি যদি কোনও পয়েন্টারকে অন্য কোনও টাইপের জন্য ফেলে দেন এবং reinterpret_castএটি আবার মূল ধরণের কাছে ফিরে আসে তবে আপনি আসল মান পাবেন। সুতরাং নিম্নলিখিত:

int* a = new int();
void* b = reinterpret_cast<void*>(a);
int* c = reinterpret_cast<int*>(b);

aএবং cএকই মান ধারণ করে তবে এর মান bঅনির্দিষ্ট। (বাস্তবে এটি প্রথাগতভাবে হিসাবে একই ঠিকানা উপস্থিত থাকবে aএবং c, কিন্তু যে মান নির্দিষ্ট নয়, এবং এটি আরো জটিল মেমরি সিস্টেমের সাথে মেশিনে সত্য নাও হতে পারে।)

কাস্টিংয়ের জন্য এবং থেকে void*, static_castপছন্দ করা উচিত be


18
আমি 'বি' অপরিজ্ঞাপিত সত্যটি পছন্দ করি। এটি আপনাকে এর সাথে নির্বোধ কাজ করা বন্ধ করে দেয়। আপনি যদি অন্য কোনও পয়েন্টার ধরণের কাছে কিছু ফেলে দেন তবে আপনি সমস্যাগুলি জিজ্ঞাসা করছেন এবং আপনি এটির উপর নির্ভর করতে পারবেন না তা আপনাকে আরও সতর্ক করে তোলে। আপনি যদি উপরে স্ট্যাটিক_কাস্ট <> ব্যবহার করেন তবে 'বি' এর ব্যবহার কী?
মার্টিন ইয়র্ক

3
আমি ভেবেছিলাম যে পুনরায় ব্যাখ্যা_কাস্ট <> একই বিট প্যাটার্নের গ্যারান্টিযুক্ত। (যা অন্য ধরণের বৈধ পয়েন্টারের সমান নয়)।
মার্টিন ইয়র্ক

37
bC ++ 11 ব্যবহার করার সময় এর মান আর নির্দিষ্ট করে দেওয়া হয় না reinterpret_cast। এবং সি ++ 03 তে একটি কাস্ট int*করার void*সাথে নিষিদ্ধ করা হয়েছিল reinterpret_cast(যদিও সংকলকরা এটি প্রয়োগ করেনি এবং এটি ব্যবহারিক ছিল না, তাই সি ++ 11 এর জন্য পরিবর্তন করা হয়েছিল)।
জোহানেস স্কাউব -

55
এটি "পুনরায় সংজ্ঞা_কাস্ট ব্যবহার কখন করবেন" এই প্রশ্নের উত্তর দেয় না।
einpoklum

6
@ লোকিআস্টারি আমার মনে হয় অনির্দিষ্টতা আপনাকে বোকা কাজ করা থেকে বিরত রাখবে না। আপনি কেবল তখনই থামান যখন আপনি এটি অনির্ধারিত মনে রাখবেন। বিশাল পার্থক্য. ব্যক্তিগতভাবে আমি অনির্ধারিত পছন্দ করি না। অনেক বেশি মনে আছে।
হেলিন ওয়াং 30'17

158

এক ক্ষেত্রে যখন reinterpret_castপ্রয়োজন যখন অস্বচ্ছ ধরনের তথ্য দিয়ে পোশাকের হয়। এটি প্রায়শই বিক্রেতা এআইপিগুলিতে ঘটে থাকে যার উপরে প্রোগ্রামারের কোনও নিয়ন্ত্রণ থাকে না। এখানে এমন একটি স্বতন্ত্র উদাহরণ যেখানে স্বেচ্ছাসেবক বিশ্বব্যাপী ডেটা সংরক্ষণ এবং পুনরুদ্ধারের জন্য একজন বিক্রেতা সরবরাহ করে একটি API:

// vendor.hpp
typedef struct _Opaque * VendorGlobalUserData;
void VendorSetUserData(VendorGlobalUserData p);
VendorGlobalUserData VendorGetUserData();

এই এপিআই ব্যবহার করতে, প্রোগ্রামারকে অবশ্যই তাদের ডেটা VendorGlobalUserDataআবার এবং পিছনে ফেলে দিতে হবে । static_castকাজ করবে না, একটি অবশ্যই ব্যবহার করতে হবে reinterpret_cast:

// main.cpp
#include "vendor.hpp"
#include <iostream>
using namespace std;

struct MyUserData {
    MyUserData() : m(42) {}
    int m;
};

int main() {
    MyUserData u;

        // store global data
    VendorGlobalUserData d1;
//  d1 = &u;                                          // compile error
//  d1 = static_cast<VendorGlobalUserData>(&u);       // compile error
    d1 = reinterpret_cast<VendorGlobalUserData>(&u);  // ok
    VendorSetUserData(d1);

        // do other stuff...

        // retrieve global data
    VendorGlobalUserData d2 = VendorGetUserData();
    MyUserData * p = 0;
//  p = d2;                                           // compile error
//  p = static_cast<MyUserData *>(d2);                // compile error
    p = reinterpret_cast<MyUserData *>(d2);           // ok

    if (p) { cout << p->m << endl; }
    return 0;
}

নীচে নমুনা এপিআই-এর একটি অনুমোদিত প্রয়োগ রয়েছে:

// vendor.cpp
static VendorGlobalUserData g = 0;
void VendorSetUserData(VendorGlobalUserData p) { g = p; }
VendorGlobalUserData VendorGetUserData() { return g; }

7
হ্যাঁ, আমি যে ভাবতে পারি তার পুনরায় ব্যাখ্যা_প্রকাশের একমাত্র অর্থবহ ব্যবহার সম্পর্কে।
জালফ

8
এটি একটি দেরিতে প্রশ্ন হতে পারে, তবে কেন বিক্রেতা এপিআই তার void*জন্য ব্যবহার করে না ?
Xoo

19
@ Xoo তারা অকার্যকর * ব্যবহার করে না কারণ সংকলনের সময় তারা (কিছু) টাইপ-চেকিং হারাবে।
jesup

4
"অস্বচ্ছ" ডেটা প্রকারের ব্যবহারিক ব্যবহারের ক্ষেত্রে হ'ল আপনি যখন সিআইতে কোনও API প্রকাশ করতে চান তবে প্রয়োগটি সি ++ তে লিখুন। আইসিইউ এমন একটি লাইব্রেরির উদাহরণ যা বিভিন্ন স্থানে এটি করে। উদাহরণস্বরূপ, স্পুফ চেকার এপিআইতে আপনি পয়েন্টারগুলির সাথে সম্পর্কিত হন USpoofChecker*যেখানে USpoofCheckerখালি কাঠামো। তবে হুডের নীচে, যখনই আপনি একটি পাস করেন USpoofChecker*, এটি reinterpret_castঅভ্যন্তরীণ সি ++ টাইপ করে।
এসএফসিসি

@ এসএফসি কেন ব্যবহারকারীর কাছে সি স্ট্রাক্ট প্রকার প্রকাশ করছেন না?
গুপ্ত

101

সংক্ষিপ্ত উত্তর: আপনি যদি জানেন reinterpret_castনা তবে এটি ব্যবহার করবেন না। ভবিষ্যতে যদি আপনার এটির প্রয়োজন হয় তবে আপনি জানতে পারবেন।

পুরো উত্তর:

আসুন বেসিক সংখ্যা টাইপ বিবেচনা করা যাক।

আপনি উদাহরণস্বরূপ রূপান্তর যখন int(12)থেকে unsigned float (12.0f)আপনার প্রসেসর চাহিদা উভয় সংখ্যার কিছু গণনার ডাকা বিভিন্ন বিট উপস্থাপনা হয়েছে। এটি কি static_castজন্য দাঁড়িয়েছে।

অন্যদিকে, আপনি যখন reinterpret_castসিপিইউ কল করেন তখন কোনও গণনা শুরু করে না। এটি কেবল মেমরিতে বিটের একটি সেটকে আচরণ করে যেমন এটির অন্য ধরণের থাকে। সুতরাং যখন আপনি রূপান্তর int*করতে float*এই শব্দ সঙ্গে, নতুন মান (পয়েন্টার dereferecing পরে) গাণিতিক অর্থ পুরনো মান সঙ্গে কিছুই করার আছে।

উদাহরণ: এটি সত্য যেreinterpret_castএক কারণেই বহনযোগ্য নয় - বাইট অর্ডার (এন্ডিয়ানেশন)। তবে এটি প্রায়শই আশ্চর্যজনকভাবে এটি ব্যবহারের সর্বোত্তম কারণ। আসুন উদাহরণটি কল্পনা করুন: আপনাকে ফাইল থেকে বাইনারি 32 বিট নম্বর পড়তে হবে এবং আপনি জানেন যে এটি বড় এন্ডিয়ান। আপনার কোডটি জেনেরিক হতে হবে এবং বড় এন্ডিয়ান (উদাহরণস্বরূপ কিছু এআরএম) এবং সামান্য এন্ডিয়ান (যেমন x86) সিস্টেমে সঠিকভাবে কাজ করতে হবে। সুতরাং আপনাকে বাইট অর্ডার পরীক্ষা করতে হবে। এটি সংকলন সময়ে সুপরিচিত তাই আপনি constexprফাংশন লিখতে পারেন : এটি অর্জনের জন্য আপনি একটি ফাংশন লিখতে পারেন:

/*constexpr*/ bool is_little_endian() {
  std::uint16_t x=0x0001;
  auto p = reinterpret_cast<std::uint8_t*>(&x);
  return *p != 0;
}

ব্যাখ্যা:x মেমরিতেবাইনারি উপস্থাপনাহতে পারে0000'0000'0000'0001(বড়) বা0000'0001'0000'0000(ছোট এন্ডিয়ান)। পুনরায় ব্যাখ্যা-কাস্টিংয়ের পরেpপয়েন্টারেরঅধীনে বাইটযথাক্রমে0000'0000বাহতে পারে0000'0001। আপনি যদি স্ট্যাটিক-0000'0001ingালাই ব্যবহার করেন তবেসর্বদা এটিই থাকবে, যাই হোক না কেন প্রান্তিকতা ব্যবহার করা হচ্ছে।

সম্পাদনা করুন:

প্রথম সংস্করণে আমি উদাহরণ ফাংশন is_little_endianহতে হবে constexpr। এটি সর্বশেষতম জিসিসিতে (8.3.0) জরিমানা সংকলন করে তবে মানকটি এটি অবৈধ says ক্ল্যাং সংকলক এটি সংকলন করতে অস্বীকার করেছে (যা সঠিক)।


1
চমৎকার উদাহরণ! আমি uint16_t এর জন্য সংক্ষিপ্ত এবং uint8_t এর স্বাক্ষরযুক্ত চার্টটি মানুষের পক্ষে এটি কম অস্পষ্ট করতে প্রতিস্থাপন করব।
জানু তুরো

@ জ্যান্টুরো- সত্য, আমরা ধরে নিতে পারি না যে shortস্মৃতিতে 16 বিট লাগে। সংশোধন।
jaskmar

1
উদাহরণটি ভুল। পুনরায় ব্যাখ্যা_কাস্টকে কনটেক্সটপ্রাপ্ত ফাংশনগুলিতে অনুমোদিত নয়
মাইকেল ভিক্সলার ১১

1
প্রথমত, এই কোডটি সর্বশেষ বিড়ম্বনা (7.0.0) এবং জিসিসি (8.2.0) উভয়ই প্রত্যাখ্যান করেছে। দুর্ভাগ্যক্রমে আমি আনুষ্ঠানিক ভাষায় সীমাবদ্ধতা পাইনি। আমি যা কিছু পেয়েছি তা হ'ল সোশ্যাল.এমএসএন.এম.সাইক্রোসফট.ফরমেশনস
মাইকেল ভিক্সলার

2
আরও সুনির্দিষ্টভাবে, en.cppreferences.com/w/cpp/language/constant_expression (আইটেম 16) পরিষ্কারভাবে বলেছে যে পুনরায় ব্যাখ্যা_কাস্ট একটি ধ্রুবক অভিব্যক্তিতে ব্যবহার করা যাবে না। এছাড়াও github.com/cplusplus/draft/blob/master/papers/N3797.pdf (5.19 ধ্রুবক অভিব্যক্তি) পৃষ্ঠা 125-126 দেখুন যা স্পষ্টভাবে পুনঃব্যবস্থাপনা_কাস্টকে বাতিল করে দেয়। তারপরে .1.১.৫ কনটেক্সটপ্রস্পেক্টর আইটেম ৫ (পৃষ্ঠা ১৪6) * একটি অ-টেম্পলেট, অ-খেলাপি বিহীন কনটেক্সটপ্রিপ ফাংশনের জন্য ... যদি কোনও যুক্তির মানগুলি এমনভাবে উপস্থিত না হয় ... তবে একটি মূল ধ্রুবক অভিব্যক্তির (5.19) মূল্যায়ন করা subexpression হতে পারে ), প্রোগ্রামটি
দুর্গঠিত

20

এর অর্থ reinterpret_castসি ++ স্ট্যান্ডার্ড দ্বারা সংজ্ঞায়িত হয় না। অতএব, তাত্ত্বিকভাবে একটি reinterpret_castআপনার প্রোগ্রাম ক্রাশ করতে পারে। অনুশীলনে সংকলকগণ আপনি যা প্রত্যাশা করেন তা করার চেষ্টা করুন, যা আপনি যা যাচ্ছেন তার বিটগুলি ব্যাখ্যা করে যেন তারা যে ধরণের আপনি কাস্ট করছেন। আপনি যদি জানেন যে আপনি যে সংকলকগুলি ব্যবহার করতে চলেছেন তারা reinterpret_cast এটি ব্যবহার করতে পারেন তবে এটি যে বহনযোগ্য তা বলতে গেলে এটি মিথ্যা বলে।

আপনি যে কেসটি বর্ণনা করেছেন তার ক্ষেত্রে এবং আপনি যে কোনও ক্ষেত্রে বিবেচনা reinterpret_castকরতে পারেন, আপনি static_castতার পরিবর্তে বা অন্য কোনও বিকল্প ব্যবহার করতে পারেন । অন্যান্য জিনিসের মধ্যে স্ট্যান্ডার্ডের কাছে আপনি কী আশা করতে পারেন সে সম্পর্কে বলতে হবে static_cast(.25.2.9):

"পয়েন্টার থেকে সিভি অকার্যকর" প্রকারের একটি মূল্য স্পষ্টভাবে পয়েন্টারটিতে অবজেক্ট টাইপের রূপান্তরিত করা যেতে পারে। অবজেক্ট টু পয়েন্টারটির একটি মানকে "পয়েন্টারকে সিভি ভয়েড" তে রূপান্তরিত করে এবং মূল পয়েন্টার টাইপের কাছে ফিরে আসার জন্য তার মূল মান থাকবে।

সুতরাং আপনার ব্যবহারের ক্ষেত্রে, এটি মোটামুটি পরিষ্কার বলে মনে হচ্ছে যে মানককরণ কমিটি আপনার ব্যবহারের উদ্দেশ্যেছিল static_cast


5
আপনার প্রোগ্রামটি বেশ ক্র্যাশ নয়। স্ট্যান্ডার্ডটি পুনরায় ব্যাখ্যা_কাস্ট সম্পর্কে কয়েকটি গ্যারান্টি দেয়। মানুষ প্রায়শই প্রত্যাশা করে না।
জলফ

1
আপনি যদি এটি সঠিকভাবে ব্যবহার করেন তবে নয়। অর্থাৎ, A থেকে B পর্যন্ত A এর পুনরায় ব্যাখ্যা_কাস্ট পুরোপুরি নিরাপদ এবং সংজ্ঞায়িত। তবে বি এর মান নির্ধারিত নয়, এবং হ্যাঁ, আপনি যদি এটির উপর নির্ভর করেন তবে খারাপ জিনিসগুলি ঘটতে পারে। তবে কাস্ট নিজেই যথেষ্ট নিরাপদ, আপনি যতক্ষণ না কেবল এটি স্ট্যান্ডার্ডের অনুমতি দেয় সেভাবে ব্যবহার করেন। ;)
জাল্ফ

55
হ্যাঁ, আমি সন্দেহ করি যে পুনরায় সংজ্ঞা_ক্র্যাশ সত্যিই আপনার প্রোগ্রামটি ক্র্যাশ করতে পারে। কিন্তু পুনরায় ব্যাখ্যা_কাস্ট করবে না। ;)
জালফ

5
<irony> আমি আমার সংকলকটিতে এটি চেষ্টা করেছিলাম এবং কোনওভাবে এটি সংকলন করতে অস্বীকার করেছিল reinterpret_crash। কোনও সংকলক ত্রুটি আমাকে পুনরায় ব্যাখ্যা করার প্রোগ্রামটি ক্রাশ করা থেকে বিরত করবে না। আমি একটি বাগ যত শীঘ্র সম্ভব প্রতিবেদন করব </ বিদ্রূপ>!
paercebal

18
@Pedabaltemplate<class T, U> T reinterpret_crash(U a) { return *(T*)nullptr; }

11

আপনি যদি (আইইইই 754) ফ্লোটে বিটওয়াইজ অপারেশন প্রয়োগ করতে চান তবে পুনরায় ব্যাখ্যা_কাস্টের একটি ব্যবহার। এর উদাহরণ হ'ল ফাস্ট ইনভার্স স্কোয়ার-রুট ট্রিক:

https://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code

এটি ভাসমানের বাইনারি উপস্থাপনাটিকে একটি পূর্ণসংখ্যা হিসাবে বিবেচনা করে, ডানদিকে স্থানান্তর করে এবং এটি একটি ধ্রুবক থেকে বিয়োগ করে, যার ফলে ক্ষতিকারককে অর্ধেক এবং অবহেলা করা হয়। একটি ফ্লোটে ফিরে রূপান্তরিত হওয়ার পরে, এটির কাছাকাছিটি আরও সঠিক করে তুলতে এটি একটি নিউটন-রাফসন পুনরাবৃত্তির শিকার হয়:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the deuce? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

এটি মূলত সিটিতে লেখা হয়েছিল, সুতরাং সি কাস্ত ব্যবহার করে, তবে সাদৃশ্য সি ++ কাস্টটি পুনরায় ব্যাখ্যা_কাস্ট।


1
error: invalid cast of an rvalue expression of type 'int64_t {aka long long int}' to type 'double&' reinterpret_cast<double&>((reinterpret_cast<int64_t&>(d) >> 1) + (1L << 61))- আইডোন
6

1
মানকটি বলে যে এটি অনির্ধারিত আচরণ: en.cppreferences.com/w/cpp/language/reinter ব্যাখ্যা_cast ("টাইপ আলিয়াসিং" এর অধীনে)
ক্রিস লুয়েংগো

@ ক্রিসলুয়েংগো যদি আমি সবকিছুর বিকল্প reinterpret_castদিয়ে থাকি তবে memcpyকি এটি এখনও ইউবি?
স্যান্ডথর্ন

@ স্যান্ডথর্ন: এটি স্ট্যান্ডার্ড অনুযায়ী ইউবি, তবে এটি যদি আপনার আর্কিটেকচারের জন্য কাজ করে তবে এটি নিয়ে চিন্তা করবেন না। আমি মনে করি, ইন্টেল আর্কিটেকচারের জন্য যেকোন সংকলকের জন্য এই কৌশলটি ঠিক আছে। এটি অন্যান্য আর্কিটেকচারগুলিতে ইচ্ছাকৃত (বা এমনকি ক্র্যাশ) হিসাবে কাজ করতে পারে না - উদাহরণস্বরূপ এটি সম্ভব হতে পারে যে ভাসমান এবং লম্বা পৃথক মেমরির বিভাগে সংরক্ষণ করা হয় (এমন কোনও আর্কিটেকচার সম্পর্কে আমি জানি না, এটি কেবল একটি যুক্তি ...) । memcpyঅবশ্যই এটি আইনী করতে হবে।
ক্রিস লুয়েংগো


2
template <class outType, class inType>
outType safe_cast(inType pointer)
{
    void* temp = static_cast<void*>(pointer);
    return static_cast<outType>(temp);
}

আমি উপসংহারে চেষ্টা করার চেষ্টা করেছি এবং টেমপ্লেটগুলি ব্যবহার করে একটি সহজ নিরাপদ কাস্ট লিখেছি। নোট করুন যে এই সমাধানটি কোনও ফাংশনে পয়েন্টার castালাইয়ের গ্যারান্টি দেয় না।


1
কি? কেন বিরক্ত হও? এটি reinterpret_castইতিমধ্যে এই পরিস্থিতিতে ইতিমধ্যে যা ঘটে থাকে: "একটি অবজেক্ট পয়েন্টার স্পষ্টভাবে একটি ভিন্ন ধরণের একটি অবজেক্ট পয়েন্টারে রূপান্তরিত হতে পারে [[ 72২ ] যখন vঅবজেক্ট পয়েন্টার টাইপের একটি অগ্রণী বস্তু পয়েন্টার টাইপ" পয়েন্টার টু সিভি T " তে রূপান্তরিত হয় , ফলাফল static_cast<cv T*>(static_cast<cv void*>(v))। " - এন 3797।
আন্ডারস্কোর_

হিসাবে c++2003স্ট্যান্ডার্ড ইনপুট করতে পারেন না যে এটি reinterpret_castআছেstatic_cast<cv T*>(static_cast<cv void*>(v))
বিদেশে Zezulinsky

1
ঠিক আছে, সত্য, তবে আমি 13 বছর আগের সংস্করণটির বিষয়ে চিন্তা করি না এবং বেশিরভাগ কোডার যদি তাদের (যেমন সম্ভবত) এড়াতে পারে তবে তাদের উচিত নয়। উত্তর এবং মন্তব্যগুলি সত্যই সর্বশেষতম উপলব্ধ স্ট্যান্ডার্ডকে প্রতিফলিত করা উচিত যদি না অন্যথায় নির্দিষ্ট করা হয় ... আইএমএইচও। যাইহোক, আমার ধারণা কমিটি 2003 এর পরে স্পষ্টভাবে এটি যুক্ত করার প্রয়োজনীয়তা অনুভব করেছে। (কারণ আইআইআরসি, এটি সি ++ 11 তে একই ছিল)
আন্ডারস্কোর_ডে

আগে C++03ছিল C++98। প্রচুর প্রকল্পগুলি বহনযোগ্য সি এর পরিবর্তে পুরানো সি ++ ব্যবহার করে Sometimes উদাহরণস্বরূপ আপনাকে সোলারিস, এআইএক্স, এইচপিইউএক্স, উইন্ডোজে একই কোডটি সমর্থন করতে হবে। এটি সংকলন নির্ভরতা এবং বহনযোগ্যতার আসে যেখানে এটি জটিল। সুতরাং একটি বহনযোগ্যতা জাহান্নাম প্রবর্তনের একটি ভাল উদাহরণ হ'ল reinterpret_castআপনার
কোডটিতে

আবার, যদি আমার মতো আপনি নিজেকে কেবলমাত্র সেই প্ল্যাটফর্মগুলিতে সীমাবদ্ধ রাখতে খুশি হন যা ভাষার সর্বশেষতম এবং সর্বশ্রেষ্ঠ সংস্করণ সহ সুন্দর খেলতে পারে তবে আপনার আপত্তিটি মূল বক্তব্য।
আন্ডারস্কোর_ডি

1

প্রথমে আপনার কাছে নির্দিষ্ট টাইপের মতো কিছু তথ্য এখানে রয়েছে যেমন:

int x = 0x7fffffff://==nan in binary representation

তারপরে আপনি অন্য ধরণের ফ্লোটের মতো একই ভেরিয়েবলটি অ্যাক্সেস করতে চান: আপনি এর মধ্যে সিদ্ধান্ত নিতে পারেন

float y = reinterpret_cast<float&>(x);

//this could only be used in cpp, looks like a function with template-parameters

অথবা

float y = *(float*)&(x);

//this could be used in c and cpp

ব্রিফ: এর অর্থ একই মেমরিটি ভিন্ন ধরণের হিসাবে ব্যবহৃত হয়। সুতরাং আপনি ভাসমানগুলির বাইনারি উপস্থাপনাগুলি উপরের মতো ইনট টাইপ হিসাবে ফ্লোটে রূপান্তর করতে পারেন। 0x80000000 উদাহরণস্বরূপ -০ (মান্টিসা এবং এক্সপোনেন্টটি শূন্য তবে সাইন, এমএসবি) এটি একটি This এটি ডাবল এবং লম্বা ডাবলগুলির জন্যও কাজ করে।

অপ্টিমাইজ: আমি মনে করি পুনরায় সংজ্ঞা_কাস্ট অনেকগুলি সংকলকগুলিতে অনুকূলিত হবে, যখন সি-কাস্টিংটি পয়েন্টারেটারিমেটিক দ্বারা তৈরি করা হয়েছে (মানটি অবশ্যই মেমোরিতে অনুলিপি করা উচিত, কারণ পয়েন্টারগুলি সিপিউ-রেজিস্টারে নির্দেশ করতে পারে না)।

দ্রষ্টব্য: উভয় ক্ষেত্রে আপনার ভোটদানের আগে ভেরিয়েবলের মধ্যে কাস্ট করা মান সংরক্ষণ করা উচিত! এই ম্যাক্রো সাহায্য করতে পারে:

#define asvar(x) ({decltype(x) __tmp__ = (x); __tmp__; })

এটি সত্য যে "এর অর্থ একই মেমরিটি ভিন্ন ধরণের হিসাবে ব্যবহৃত হয়" তবে এটি নির্দিষ্ট জোড়া টাইপের মধ্যে সীমাবদ্ধ। আপনার উদাহরণে reinterpret_castফর্ম intথেকে float&অনির্ধারিত আচরণ।
jaskmar

1

ব্যবহারের একটি কারণ reinterpret_castহ'ল যখন কোনও বেস ক্লাসের একটি ভিটিবেল থাকে না, তবে একটি উত্পন্ন শ্রেণি থাকে। সেক্ষেত্রে , static_castএবং reinterpret_castবিভিন্ন পয়েন্টার মানগুলির ফলাফল হবে (এটি উপরের জাল্ফ দ্বারা উল্লিখিত এটাইপিকাল কেস হবে )। কেবল একটি অস্বীকৃতি হিসাবে, আমি উল্লেখ করছি না যে এটি স্ট্যান্ডার্ডের একটি অংশ, তবে বিভিন্ন বিস্তৃত সংকলকগুলির বাস্তবায়ন।

উদাহরণ হিসাবে, নীচের কোডটি নিন:

#include <cstdio>

class A {
public:
    int i;
};

class B : public A {
public:
    virtual void func() {  }
};

int main()
{
    B b;
    const A* a = static_cast<A*>(&b);
    const A* ar = reinterpret_cast<A*>(&b);

    printf("&b = %p\n", &b);
    printf(" a = %p\n", a);
    printf("ar = %p\n", ar);
    printf("difference = %ld\n", (long int)(a - ar));

    return 0;
}

যা এরকম কিছু তৈরি করে:

& বি = 0x7ffe10e68b38
a = 0x7ffe10e68b40
আর = 0x7ffe10e68b38
পার্থক্য = 2

সব কম্পাইলার আমি চেষ্টা ইন - (MSVC 2015 & 2017, ঝনঝন শব্দ 8.0.0, জিসিসি 9.2, আইসিসি 19.0.1 দেখতে গত 3 জন্য godbolt ফল) static_castযা থেকে পৃথক reinterpret_cast2 দ্বারা (MSVC জন্য 4)। পার্থক্য সম্পর্কে সতর্ক করার একমাত্র সংকলকটি ছিল ঝাঁকুনি সহ:

17:16: সতর্কতা: 'reinterpret_cast' ক্লাস থেকে নন-জিরো তার বেস অফসেট 'বি *' 'এ *' 'static_cast' [-Wreinterpret-বেস ক্লাসের] থেকে ভিন্নভাবে আচরণ করবে
const একটি * আরবী ভাষায় = reinterpret_cast (& খ) ;
^ ~~~~~~~~~~~~~~~~~~~~~~~
17:16: নোট: ব্যবহার 'static_cast' সঠিকভাবে পয়েন্টার সামঞ্জস্য যখন upcasting
const একটি * আরবী ভাষায় = reinterpret_cast (& খ) ;
। ic
স্ট্যাটিক_কাস্ট

একটা শেষ সতর্কীকরণ যে যদি বেস বর্গ কোন তথ্য সদস্য রয়েছে (যেমন হয় int i;) তাহলে ঝনঝন, জিসিসি, এবং আইসিসি একই ঠিকানায় জন্য ফিরে reinterpret_castজন্য static_cast, যেহেতু MSVC এখনও না।


1

এখানে আভি গিন্সবার্গের প্রোগ্রামের একটি বৈকল্পিক রয়েছে যা reinterpret_castক্রিস লুয়েংগো, ফ্লডিন এবং সেন্টিমিডিপি দ্বারা উল্লিখিত সম্পত্তিটিকে স্পষ্টভাবে চিত্রিত করে : সংকলকটি পয়েন্ট-টু মেমরির অবস্থানটি এমনভাবে আচরণ করে যেন এটি নতুন ধরণের একটি বস্তু were

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

class A
{
public:
    int i;
};

class B : public A
{
public:
    virtual void f() {}
};

int main()
{
    string s;
    B b;
    b.i = 0;
    A* as = static_cast<A*>(&b);
    A* ar = reinterpret_cast<A*>(&b);
    B* c = reinterpret_cast<B*>(ar);

    cout << "as->i = " << hex << setfill('0')  << as->i << "\n";
    cout << "ar->i = " << ar->i << "\n";
    cout << "b.i   = " << b.i << "\n";
    cout << "c->i  = " << c->i << "\n";
    cout << "\n";
    cout << "&(as->i) = " << &(as->i) << "\n";
    cout << "&(ar->i) = " << &(ar->i) << "\n";
    cout << "&(b.i) = " << &(b.i) << "\n";
    cout << "&(c->i) = " << &(c->i) << "\n";
    cout << "\n";
    cout << "&b = " << &b << "\n";
    cout << "as = " << as << "\n";
    cout << "ar = " << ar << "\n";
    cout << "c  = " << c  << "\n";

    cout << "Press ENTER to exit.\n";
    getline(cin,s);
}

এর ফলাফল হিসাবে এর ফলাফল:

as->i = 0
ar->i = 50ee64
b.i   = 0
c->i  = 0

&(as->i) = 00EFF978
&(ar->i) = 00EFF974
&(b.i) = 00EFF978
&(c->i) = 00EFF978

&b = 00EFF974
as = 00EFF978
ar = 00EFF974
c  = 00EFF974
Press ENTER to exit.

এটি দেখা যায় যে বি অবজেক্টটি মেমোরিতে প্রথমে বি-নির্দিষ্ট ডেটা হিসাবে নির্মিত হয়, তার পরে এমবেডড একটি অবজেক্ট থাকে। static_castসঠিকভাবে এমবেডেড একটি বস্তুর ঠিকানা ফেরৎ, এবং পয়েন্টার দ্বারা নির্মিত static_castসঠিকভাবে তথ্য ক্ষেত্রের মান দেয়। reinterpret_castআচরণগুলি দ্বারা উত্পাদিত পয়েন্টারb মেমোরি অবস্থানের যেন এটি একটি সরল A অবজেক্ট এবং তাই যখন পয়েন্টার ডেটা ফিল্ড পাওয়ার চেষ্টা করে তখন কিছু বি-নির্দিষ্ট ডেটা ফেরত দেয় যেন এটি এই ক্ষেত্রের বিষয়বস্তু were

এর একটি ব্যবহার reinterpret_castহ'ল একটি পয়েন্টারকে স্বাক্ষরবিহীন পূর্ণসংখ্যায় রূপান্তর করা (যখন পয়েন্টার এবং স্বাক্ষরবিহীন পূর্ণসংখ্যা একই আকার হয়):

int i; unsigned int u = reinterpret_cast<unsigned int>(&i);


-6

দ্রুত উত্তর: static_castএটি সংকলিত হলে ব্যবহার করুন , অন্যথায় অবলম্বন করুন reinterpret_cast


-16

এফএকিউ পড়ুন ! সিতে সি ++ ডেটা রাখা ঝুঁকিপূর্ণ হতে পারে।

সি ++ তে কোনও বস্তুর বিন্দু বিন্দুতে void *কোনও বর্ণ ছাড়াই রূপান্তরিত হতে পারে । তবে এটি অন্যভাবে সত্য নয়। static_castআসল পয়েন্টারটি ফিরে পেতে আপনার প্রয়োজন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.