কড়া আলিয়াজিংয়ের নিয়ম কী?


803

সিতে সাধারণ অপরিবর্তিত আচরণ সম্পর্কে জিজ্ঞাসা করার সময়, লোকেরা মাঝে মধ্যে কঠোর আলিয়াজিং বিধি উল্লেখ করে।
তারা কী সম্পর্কে কথা বলছে?


12
@ বেন ভয়েগ্ট: সি ++ এবং সি এর জন্য এলিয়াসিংয়ের নিয়মগুলি আলাদা। কেন এই প্রশ্নটি ট্যাগ করা হয় cএবং এর সাথে c++faq
মাইক এমবি

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

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

অন্যদিকে, আমি সম্মত হই যে অনেক ভাল উত্তর পোস্ট হওয়ার পরে প্রশ্নটি পরিবর্তন করা সমস্যাযুক্ত এবং সমস্যাটি যাইহোক সমস্যাটি একটি গৌণ বিষয়।
মাইকএমবি

1
@ মাইকএমবি: আমি মনে করি আপনি দেখতে পাবেন যে গৃহীত উত্তরের উপর সি ফোকাস, এটি সি ++ এর জন্য ভুল করে, একটি তৃতীয় পক্ষ সম্পাদনা করেছে। সেই অংশটি সম্ভবত আবার সংশোধন করা উচিত।
বেন ভয়েগট

উত্তর:


561

একটা প্রচলিত অবস্থা যেখানে আপনি কঠোর এলিয়াসিং সমস্যার সম্মুখীন হন যখন শব্দ (একটি পয়েন্টার মত আপনার সিস্টেম আকার একটি বাফার সম্মুখের একটি struct (ক ডিভাইস / নেটওয়ার্ক বার্তা মত) ওভারলেয়িং হয় uint32_ts অথবা uint16_tগুলি)। আপনি যখন এই জাতীয় বাফারের উপর কোনও কাঠামোকে আবৃত করেন বা পয়েন্টার castালাইয়ের মাধ্যমে কোনও স্টাফের উপর কোনও বাফার আপনি সহজেই কঠোর আলিয়াজিং বিধি লঙ্ঘন করতে পারেন।

সুতরাং এই ধরণের সেটআপে, আমি যদি কোনও কিছুর কাছে একটি বার্তা পাঠাতে চাই তবে আমার দুটি বেমানান পয়েন্টার একই মেমরির অংশের দিকে ইঙ্গিত করতে হবে। আমি তখন নির্লজ্জভাবে এই জাতীয় কিছু (কোড সহ sizeof(int) == 2) কোড করতে পারি :

typedef struct Msg
{
    unsigned int a;
    unsigned int b;
} Msg;

void SendWord(uint32_t);

int main(void)
{
    // Get a 32-bit buffer from the system
    uint32_t* buff = malloc(sizeof(Msg));

    // Alias that buffer through message
    Msg* msg = (Msg*)(buff);

    // Send a bunch of messages    
    for (int i =0; i < 10; ++i)
    {
        msg->a = i;
        msg->b = i+1;
        SendWord(buff[0]);
        SendWord(buff[1]);   
    }
}

কঠোর আলিয়াজিং বিধিটি এই সেটআপটিকে অবৈধ করে তোলে: সিআই 2011 6.5 অনুচ্ছেদ 7 1 এর দ্বারা অনুমোদিত এমন কোনও বস্তু যে সামঞ্জস্যপূর্ণ ধরণের নয় বা অন্য কোনও ধরণের নয় এমন একটি পয়েন্টারকে ডিফারেন্স করা অনির্ধারিত আচরণ। দুর্ভাগ্যবশত, আপনি করতে পারেন এখনও কোডটির এই পথ, হয়তো কিছু সতর্কবার্তা পেতে, এটা কম্পাইল জরিমানা, শুধুমাত্র অদ্ভুত অপ্রত্যাশিত আচরণের যখন আপনি কোড রান আছে।

(জিসিসি এলিয়াসিং সতর্কতা দেওয়ার ক্ষমতায় কিছুটা অসঙ্গত দেখা যায়, কখনও কখনও আমাদের বন্ধুত্বপূর্ণ সতর্কতা দেয় এবং কখনও কখনও তা দেয় না))

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

মনে রাখবেন, যদি আপনি মনে করেন যে উদাহরণটি সংবিধানযুক্ত, আপনি যদি অন্য কোনও ফাংশনটিতে বাফারটি পাঠাচ্ছেন তবে আপনার জন্য প্রেরণ করছেন, যদি আপনার পরিবর্তে থাকে।

void SendMessage(uint32_t* buff, size_t size32)
{
    for (int i = 0; i < size32; ++i) 
    {
        SendWord(buff[i]);
    }
}

এবং এই সুবিধাজনক ফাংশনটির সুবিধা নিতে আমাদের পূর্বের লুপটি আবারও লিখুন

for (int i = 0; i < 10; ++i)
{
    msg->a = i;
    msg->b = i+1;
    SendMessage(buff, 2);
}

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

সুতরাং আমি কিভাবে এই কাছাকাছি পেতে পারি?

  • একটি ইউনিয়ন ব্যবহার করুন। বেশিরভাগ সংকলক কঠোর আলিয়াজিংয়ের অভিযোগ না করেই এটি সমর্থন করে। এটি C99 এ অনুমোদিত এবং স্পষ্টভাবে C11 এ অনুমোদিত।

    union {
        Msg msg;
        unsigned int asBuffer[sizeof(Msg)/sizeof(unsigned int)];
    };
    
  • আপনি আপনার সংকলকটিতে কঠোর আলিয়াজিং অক্ষম করতে পারেন ( চ [no-] কঠোর-এলিয়াসিং জিসিসি))

  • আপনি char*আপনার সিস্টেমের শব্দের পরিবর্তে এলিয়াসিংয়ের জন্য ব্যবহার করতে পারেন । নিয়মগুলি char*(সহ signed charএবং unsigned char) এর জন্য ব্যতিক্রমের অনুমতি দেয় । এটি সর্বদা ধরে নেওয়া হয় যে char*অন্য ধরণের নাম রাখে। তবে এটি অন্যভাবে কাজ করবে না: আপনার কাঠামোটি অক্ষরের একটি বাফারটিকে অন্যরকমভাবে রাখবে এমন কোনও ধারণা নেই।

সূচনা সাবধান

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

পাদটীকা

1 সি 2011 6.5 7 প্রকারের মধ্যে একটি লভ্যালুকে অ্যাক্সেসের অনুমতি দেয় সেগুলি হ'ল:

  • বস্তুর কার্যকর ধরণের সাথে সামঞ্জস্যপূর্ণ এক প্রকার,
  • বস্তুর কার্যকর ধরণের সাথে সামঞ্জস্যপূর্ণ কোনও ধরণের একটি যোগ্য সংস্করণ,
  • এমন এক ধরণের যা বস্তুর কার্যকর ধরণের সাথে সম্পর্কিত স্বাক্ষরযুক্ত বা স্বাক্ষরযুক্ত প্রকার,
  • এমন এক ধরণের যা বস্তুর কার্যকর ধরণের কার্যকর সংস্করণের সাথে সম্পর্কিত স্বাক্ষরযুক্ত বা স্বাক্ষরযুক্ত প্রকার,
  • একটি সামগ্রিক বা ইউনিয়ন প্রকার যা এর সদস্যদের মধ্যে পূর্বোক্ত ধরণের একটি অন্তর্ভুক্ত করে (অন্তর্ভুক্ত, পুনরাবৃত্তভাবে, একটি সাবগ্রেগেটের সদস্য বা সমন্বিত ইউনিয়নের সদস্য সহ), বা
  • একটি অক্ষর টাইপ।

16
আমি যুদ্ধের পরে আসছি বলে মনে হচ্ছে .. এর পরিবর্তে কি unsigned char*ব্যবহৃত হতে পারে char*? আমি অন্তর্নিহিত ধরণের unsigned charপরিবর্তে এর চেয়ে বেশি ব্যবহার করার প্রবণতা রাখি কারণ আমার বাইটগুলি স্বাক্ষরিত নয় এবং আমি স্বাক্ষরিত আচরণের অদ্ভুততা চাই না (উল্লেখযোগ্যভাবে উপচে পড়া charbyte
ওঠা

30
@ ম্যাথিউঃ: স্বাক্ষর করা উপন্যাসের বিধিগুলিতে কোনও পার্থক্য করে না, তাই ব্যবহার unsigned char *করা ঠিক আছে।
টমাস এডিং

22
ইউনিয়ন সদস্যের কাছ থেকে পড়া শেষের লিখিত চেয়ে পৃথক করা আচরণ কি নয়?
আর মার্টিনহো ফার্নান্দেস

23
বোলকস, এই উত্তরটি সম্পূর্ণ পিছনের দিকে । এটি অবৈধ হিসাবে প্রদর্শিত উদাহরণটি আইনী এবং এটি আইনী হিসাবে প্রদর্শিত উদাহরণটি অবৈধ।
আর মার্টিনহো ফার্নান্দিস

7
আপনার uint32_t* buff = malloc(sizeof(Msg));এবং পরবর্তী ইউনিয়ন unsigned int asBuffer[sizeof(Msg)];বাফার ঘোষণার বিভিন্ন মাপ থাকবে এবং দুটিও সঠিক নয়। mallocকল ফণা অধীন 4 বাইট প্রান্তিককরণ উপর নির্ভর করা হয় (এটা করতে না) এবং ইউনিয়ন 4 বার বড় তুলনায় এটি করা প্রয়োজন হতে হবে ... আমি বুঝতে পারি যে এটা স্বচ্ছতার জন্য কিন্তু এটা বাগ আমাকে কেউ-the- কম ...
নন-সংক্ষিপ্ত

233

আমি যে সর্বোত্তম ব্যাখ্যাটি পেয়েছি তা হ'ল মাইক অ্যাক্টন, স্ট্যান্ডার্ড এলিয়াসিং বোঝা । এটি পিএস 3 বিকাশের দিকে কিছুটা ফোকাস করেছে, তবে এটি মূলত কেবল জিসিসি।

নিবন্ধ থেকে:

"স্ট্রাইক অ্যালাইজিং হ'ল একটি অনুমান যা সি (বা সি ++) সংকলক দ্বারা তৈরি করা হয় যে বিভিন্ন ধরণের বস্তুর প্রতি পয়েন্টারগুলি ডিপ্রিফারেন্সিং কখনও একই মেমরি অবস্থানের (যেমন একে অপরকে ওরফে।) উল্লেখ করে না" "

সুতরাং মূলত যদি আপনার কোনও int*স্মৃতিযুক্ত একটি স্মৃতিযুক্ত থাকে intএবং তারপরে আপনি float*সেই স্মৃতিতে একটি নির্দেশ করেন এবং এটি floatনিয়ম ভঙ্গ করে হিসাবে ব্যবহার করেন। যদি আপনার কোড এটি সম্মান না করে তবে সংকলকের অপ্টিমাইজারটি সম্ভবত আপনার কোডটি ভেঙে দেবে।

নিয়মের ব্যতিক্রম ক char*, যা কোনও প্রকারের দিকে নির্দেশ করার অনুমতিপ্রাপ্ত is


6
সুতরাং বৈধভাবে 2 বিভিন্ন ধরণের ভেরিয়েবলের সাথে একই মেমরিটি ব্যবহার করার সাধারণ উপায় কী? বা সবাই কি শুধু কপি করে?
jiggunjer

4
মাইক অ্যাক্টনের পৃষ্ঠাটি ত্রুটিযুক্ত। "ইউনিয়ন (2) মাধ্যমে কাস্টিং" এর অংশটি অন্তত: সম্পূর্ণরূপে ভুল; তিনি যে কোডটি আইনী বলে দাবি করেছেন তা নয়।
ডেভম্যাক

11
@ ড্যাভম্যাক: সি 89 এর লেখকরা কখনোই উদ্দেশ্য করেননি যে এটি প্রোগ্রামারদের হুপের মধ্য দিয়ে ঝাঁপিয়ে পড়তে বাধ্য করা উচিত। আমি ধারণাটি পুরোপুরি উদ্ভট বলে মনে করি যে অপ্টিমাইজেশনের একমাত্র উদ্দেশ্যে বিদ্যমান একটি নিয়মটি এমন ফ্যাশনে ব্যাখ্যা করা উচিত যাতে প্রোগ্রামারদের কোড লিখতে হবে যে কোনও অপ্টিমাইজার অপ্রয়োজনীয় কোডটি সরিয়ে ফেলবে এই প্রত্যাশায় ডেটা অনুলিপি করে অনুলিপি করে।
সুপারক্যাট

1
@ কুরিয়াসগুই: "ইউনিয়ন থাকতে পারে না"? প্রথমত, ইউনিয়নগুলির মূল / প্রাথমিক উদ্দেশ্য কোনওভাবেই এলিয়াস সম্পর্কিত নয়। দ্বিতীয়ত, আধুনিক ভাষার স্পেসটি এলিয়াসিংয়ের জন্য ইউনিয়নগুলি স্পষ্টভাবে অনুমতি দেয়। সংঘটিতকারীকে লক্ষ্য করতে হবে যে একটি ইউনিয়ন ব্যবহৃত হয়েছে এবং পরিস্থিতিটির একটি বিশেষ উপায় treat
এএনটি

5
@ কুরিয়াসগুই: ভুয়া প্রথমত, ইউনিয়নগুলির পিছনে মূল ধারণাগত ধারণাটি ছিল যে কোনও মুহুর্তে প্রদত্ত ইউনিয়ন অবজেক্টে কেবলমাত্র একটি সদস্য অবজেক্ট "সক্রিয়" রয়েছে, অন্যরা কেবল অস্তিত্বের অস্তিত্ব রাখে না। সুতরাং, আপনার বিশ্বাস বলে মনে হয় এমন কোনও "একই ঠিকানায় আলাদা আলাদা জিনিস" নেই। দ্বিতীয়ত, অ্যালাইজিং লঙ্ঘনের প্রত্যেকে যার যার সাথে কথা বলছে তা হ'ল একটি অবজেক্টকে আলাদা আলাদা বস্তু হিসাবে অ্যাক্সেস করার বিষয়ে, কেবল একই ঠিকানা সহ দুটি বস্তু থাকার বিষয়ে নয় । যতক্ষণ না টাইপ-পানিং অ্যাক্সেস না থাকে ততক্ষণ কোনও সমস্যা নেই। এটাই ছিল মূল ধারণা। পরে, ইউনিয়নগুলির মাধ্যমে টাইপ-পানিংয়ের অনুমতি দেওয়া হয়েছিল।
এএনটি

133

এটি হ'ল কঠোর আলিয়াজিং নিয়ম, সি ++ ০৩ স্ট্যান্ডার্ডের ৩.১০ বিভাগে পাওয়া গেছে (অন্যান্য উত্তরগুলি ভাল ব্যাখ্যা সরবরাহ করে তবে কোনওটিই বিধিটি সরবরাহ করে না):

যদি কোনও প্রোগ্রাম নিম্নলিখিত ধরণের একটি ব্যতীত অন্য কোনও লভ্যালুয়ের মাধ্যমে কোনও অবজেক্টের সঞ্চিত মান অ্যাক্সেস করার চেষ্টা করে তবে আচরণটি সংজ্ঞায়িত হয়:

  • বস্তুর গতিশীল প্রকার,
  • বস্তুর গতিশীল ধরণের একটি সিভি-যোগ্য সংস্করণ,
  • এমন এক ধরণের যা স্বাক্ষরিত বা স্বাক্ষরযুক্ত প্রকার যা অবজেক্টটির গতিশীল প্রকারের সাথে সম্পর্কিত,
  • এমন এক ধরণের যা স্বাক্ষরিত বা স্বাক্ষরযুক্ত প্রকার যা বস্তুর গতিশীল প্রকারের সিভি-যোগ্য সংস্করণের সাথে সম্পর্কিত,
  • একটি সামগ্রিক বা ইউনিয়ন প্রকার যা এর সদস্যদের মধ্যে পূর্বোক্ত ধরণের একটি অন্তর্ভুক্ত করে (অন্তর্ভুক্ত, পুনরাবৃত্তভাবে, একটি সাবগ্রেগেটের সদস্য বা সমন্বিত ইউনিয়নের সদস্য সহ),
  • একটি প্রকার যা (সম্ভবত সিভি-কোয়ালিটিভড) অবজেক্টের গতিশীল প্রকারের বেস শ্রেণীর ধরণ,
  • একটি charবা unsigned charটাইপ।

সি ++ 11 এবং সি ++ 14 শব্দগুচ্ছ (পরিবর্তনগুলি জোর দিয়েছিল):

যদি কোনও প্রোগ্রাম নিম্নলিখিত ধরণের একটি ব্যতীত অন্য কোনও গ্লুভের মাধ্যমে কোনও অবজেক্টের সঞ্চিত মান অ্যাক্সেস করার চেষ্টা করে তবে আচরণটি সংজ্ঞায়িত:

  • বস্তুর গতিশীল প্রকার,
  • বস্তুর গতিশীল ধরণের একটি সিভি-যোগ্য সংস্করণ,
  • বস্তুর গতিশীল ধরণের সাথে একই ধরণের (4.4-তে সংজ্ঞায়িত),
  • এমন এক ধরণের যা স্বাক্ষরিত বা স্বাক্ষরযুক্ত প্রকার যা অবজেক্টটির গতিশীল প্রকারের সাথে সম্পর্কিত,
  • এমন এক ধরণের যা স্বাক্ষরিত বা স্বাক্ষরযুক্ত প্রকার যা বস্তুর গতিশীল প্রকারের সিভি-যোগ্য সংস্করণের সাথে সম্পর্কিত,
  • একটি সামগ্রিক বা ইউনিয়ন প্রকার যা এর উপাদান বা অ স্থিতিশীল ডেটা সদস্যদের মধ্যে পূর্বোক্ত ধরণের একটি অন্তর্ভুক্ত করে (অন্তর্ভুক্ত, পুনরাবৃত্তভাবে, একটি উপজাতি বা অন্তর্ভুক্ত ইউনিয়নের একটি উপাদান বা অ স্থির ডেটা সদস্য সহ),
  • একটি প্রকার যা (সম্ভবত সিভি-কোয়ালিটিভড) অবজেক্টের গতিশীল প্রকারের বেস শ্রেণীর ধরণ,
  • একটি charবা unsigned charটাইপ।

দুটি পরিবর্তন ছোট ছিল: লভালুর পরিবর্তে গ্লাভ্যু এবং সমষ্টি / ইউনিয়ন মামলার ব্যাখ্যা।

তৃতীয় পরিবর্তনটি আরও শক্তিশালী গ্যারান্টি দেয় (শক্তিশালী আলিয়াজিং নিয়ম শিথিল করে): অনুরূপ ধরণের নতুন ধারণা যা এখন ওরফে নিরাপদ।


এছাড়াও সি শব্দবন্ধ ( সি 99; আইএসও / আইসিসি 9899: 1999 6.5 / 7; ঠিক একই শব্দটি আইএসও / আইইসি 9899: 2011 §6.5 ¶7 এ ব্যবহৃত হয়):

একটি অবজেক্টের তার সঞ্চিত মানটি কেবলমাত্র একটি মূল্যবান এক্সপ্রেশন দ্বারা অ্যাক্সেস করতে হবে যা নিম্নলিখিত ধরণের 73৩ ) বা 88) :

  • বস্তুর কার্যকর ধরণের সাথে সামঞ্জস্যপূর্ণ এক প্রকার,
  • বস্তুর কার্যকর ধরণের সাথে সামঞ্জস্যপূর্ণ প্রকারের একটি কোয়ালিড সংস্করণ,
  • এমন এক ধরণের যা বস্তুর কার্যকর ধরণের সাথে সম্পর্কিত স্বাক্ষরযুক্ত বা স্বাক্ষরযুক্ত প্রকার,
  • এমন এক ধরণের যা বস্তুর কার্যকর ধরণের কোনও গুণমান সংস্করণের সাথে স্বাক্ষরযুক্ত বা স্বাক্ষরযুক্ত প্রকার,
  • একটি সামগ্রিক বা ইউনিয়ন প্রকার যা এর সদস্যদের মধ্যে পূর্বোক্ত ধরণের একটি অন্তর্ভুক্ত করে (অন্তর্ভুক্ত, পুনরাবৃত্তভাবে, একটি সাবগ্রেগেটের সদস্য বা সমন্বিত ইউনিয়নের সদস্য সহ), বা
  • একটি অক্ষর টাইপ।

)৩) বা ৮৮) এই তালিকার উদ্দেশ্যটি সেই পরিস্থিতিতে নির্দিষ্ট করা যা কোনও বস্তু অ্যালাইজড হতে পারে বা নাও করতে পারে।


7
বেন, লোকেরা এখানে প্রায়শই নির্দেশিত হওয়ায় আমি সম্পূর্ণতার স্বার্থে নিজেকেও সি মানের সাথে রেফারেন্স যুক্ত করার অনুমতি দিয়েছি।
কোস

1
C89 যুক্তি cs.technion.ac.il/users/yechiel/CS/C++traft/rationale.pdf বিভাগটি দেখুন 3.3 যা এ সম্পর্কে আলোচনা করে।
ফোরগান 1

2
যদি কারও কাঠামোর ধরণের লভ্যালু থাকে, কোনও সদস্যের ঠিকানা নেয় এবং এটি কোনও ফাংশনে পাস করে যেটি সদস্য প্রকারের জন্য এটি পয়েন্টার হিসাবে ব্যবহার করে, তবে কি সেই সদস্যের কোনও আইনের অ্যাক্সেস হিসাবে বিবেচিত হবে (আইনী), বা কাঠামোর ধরণের কোন জিনিস (নিষিদ্ধ)? একজন অনেক কোডের এটা যেমন ফ্যাশন এক্সেস কাঠামো করার বৈধতা পাবে অনুমান, এবং আমি মনে করি মানুষের অনেক একটি নিয়ম যা ক্রিয়া বাধা দিত হিসেবে বোঝা হয়েছিল কোঁ কোঁ করা হবে, কিন্তু এটা স্পষ্ট নয় কি সঠিক নিয়ম আছে। আরও, ইউনিয়ন এবং কাঠামো একই আচরণ করা হয়, তবে প্রত্যেকের জন্য বুদ্ধিমান নিয়ম আলাদা হওয়া উচিত।
সুপারক্যাট

2
@ সুপের্যাট: কাঠামোর নিয়মটি যেভাবে শব্দযুক্ত, প্রকৃত অ্যাক্সেস সর্বদা আদিম ধরণের to তারপরে আদিম ধরণের রেফারেন্সের মাধ্যমে অ্যাক্সেস আইনী কারণ প্রকারগুলি মিলছে এবং ধারণকৃত কাঠামোর ধরণের রেফারেন্সের মাধ্যমে অ্যাক্সেস আইনী কারণ এটি বিশেষভাবে অনুমোদিত।
বেন ভয়েগট

2
@ বেনওয়েগট: ইউনিয়নের মাধ্যমে অ্যাক্সেস না করা হলে সাধারণ প্রাথমিক ক্রম কাজ করে বলে আমি মনে করি না। Gcc কী করছে তা দেখতে goo.gl/HGOyoK দেখুন । যদি কোনও সদস্য প্রকারের লভালু (ইউনিয়ন-সদস্য-অ্যাক্সেস অপারেটর ব্যবহার না করা) এর মাধ্যমে ইউনিয়ন প্রকারের একটি লভ্যালু অ্যাক্সেস করা আইনী ছিল, তবে wow(&u->s1,&u->s2)পয়েন্টারটি সংশোধন করার জন্য ব্যবহার করা হলেও আইনি হতে হবে u, এবং এটি বেশিরভাগ অপ্টিমাইজেশানকে অস্বীকার করবে এলিয়াসিং বিধিটি সুবিধার্থে ডিজাইন করা হয়েছিল।
সুপারকেট

80

বিঃদ্রঃ

এটি আমার "স্ট্রাক্ট আলিয়াজিং বিধি কী এবং আমরা কেন যত্ন নিই?" থেকে উদ্ধৃত লেখা.

কড়া আলিয়াজিং কি?

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

দুর্ভাগ্যক্রমে কড়া আলিয়াস লঙ্ঘনের কারণে আমরা প্রায়শই আমাদের প্রত্যাশার ফলাফলগুলি পেয়ে যাব, সম্ভাবনাটি নতুন অপ্টিমাইজেশান সহ সংকলকটির ভবিষ্যতের সংস্করণটি কোডটিকে ভঙ্গ করবে যা আমরা ভেবেছিলাম। এটি অনাকাঙ্ক্ষিত এবং কঠোর এলিয়াসিং বিধি এবং সেগুলি কীভাবে লঙ্ঘন করা এড়ানো যায় তা বোঝা একটি উপযুক্ত লক্ষ্য।

আমরা কেন যত্ন নিই সে সম্পর্কে আরও জানার জন্য, আমরা কঠোর আলিয়াজিং বিধি লঙ্ঘন করার সময় যে বিষয়গুলি সামনে আসে সেগুলি নিয়ে আলোচনা করব, টাইপ পেনিংয়ে ব্যবহৃত সাধারণ কৌশলগুলি প্রায়শই কঠোর আলিয়াজিং বিধি লঙ্ঘন করে এবং কীভাবে সঠিকভাবে শাস্তি টাইপ করতে হয় সেগুলি নিয়ে আলোচনা করব।

প্রাথমিক উদাহরণ

আসুন কয়েকটি উদাহরণগুলি দেখুন, তারপরে আমরা মানক (গুলি) ঠিক কী বলেছে সে সম্পর্কে কথা বলতে পারি, আরও কয়েকটি উদাহরণ পরীক্ষা করে দেখুন এবং তারপরে কীভাবে কঠোরভাবে এলিয়াসিং এড়ানো যায় এবং কীভাবে আমরা মিস করেছি তা লঙ্ঘন করতে পারি। এখানে এমন একটি উদাহরণ রয়েছে যা অবাক হওয়ার মতো নয় ( সরাসরি উদাহরণ ):

int x = 10;
int *ip = &x;

std::cout << *ip << "\n";
*ip = 12;
std::cout << x << "\n";

আমাদের কাছে একটি অন্তর্নিহিত * কোনও ইন্টি দ্বারা দখলকৃত মেমরিটির দিকে ইঙ্গিত করছে এবং এটি একটি বৈধ আলিয়াসিং। অপ্টিমাইজারটি ধরে নিতে হবে যে আইপি এর মাধ্যমে অ্যাসাইনমেন্টগুলি এক্স দ্বারা দখল করা মান আপডেট করতে পারে ।

পরবর্তী উদাহরণটি অ্যালিজিং দেখায় যা অপরিজ্ঞাত আচরণের দিকে পরিচালিত করে ( সরাসরি উদাহরণ ):

int foo( float *f, int *i ) { 
    *i = 1;               
    *f = 0.f;            

   return *i;
}

int main() {
    int x = 0;

    std::cout << x << "\n";   // Expect 0
    x = foo(reinterpret_cast<float*>(&x), &x);
    std::cout << x << "\n";   // Expect 0?
}

ফাংশন ফুতে আমরা একটি ইনট * এবং একটি ফ্লোট * নিই, এই উদাহরণে আমরা foo কল করি এবং উভয় পরামিতি একই মেমরি অবস্থানের দিকে নির্দেশ করি যা এই উদাহরণে কোনও int থাকে । মনে রাখবেন, reinterpret_cast অভিব্যক্তি চিকিত্সা হিসাবে যদি এটি টাইপ তার টেমপ্লেট প্যারামিটার দ্বারা specificed ছিল কম্পাইলার কহন হয়। এক্ষেত্রে আমরা এটিকে এক্সপ্রেশন এবং এক্স এর সাথে আচরণ করতে বলছি যেন এটিতে টাইপ * রয়েছে । আমরা naively দ্বিতীয় ফল আশা করতে পারে cout হতে 0 কিন্তু অপ্টিমাইজেশান এর মাধ্যমে ব্যবহার সক্রিয় -O2 উভয় জিসিসি এবং ঝনঝন নিম্নলিখিত ফল:

0
1

যা প্রত্যাশিত নাও হতে পারে তবে পুরোপুরি বৈধ কারণ আমরা অনির্ধারিত আচরণটি শুরু করেছি inv একটি ভাসাটি বৈধভাবে কোনও ইনট অবজেক্ট ওরফে করতে পারে না । অতএব অপ্টিমাইজারটি ধ্রুব 1 টি সঞ্চিত করতে পারে যখন নির্ধারণের সময় আমি ফিরতি মান হব যেহেতু চ এর মাধ্যমে কোনও স্টোর বৈধভাবে কোনও ইনট অবজেক্টকে প্রভাবিত করতে পারে না । কম্পাইলার এক্সপ্লোরার কোডটি প্লাগ করে দেখায় এটি ঠিক ঘটছে ( সরাসরি উদাহরণ ):

foo(float*, int*): # @foo(float*, int*)
mov dword ptr [rsi], 1  
mov dword ptr [rdi], 0
mov eax, 1                       
ret

ব্যবহার অপটিমাইজার প্রকার ভিত্তিক ওরফে বিশ্লেষণ (TBAA) অনুমান 1 ফেরত পাঠানো হবে এবং সরাসরি রেজিস্টার মধ্যে ধ্রুবক রয়েছে যার মান চলে আসে EAX ফেরত মান বহন করে যা। টিবিএএ লোড এবং স্টোরগুলি অনুকূলকরণের জন্য কী ধরণের উপন্যাসের অনুমতি দেয় সে সম্পর্কে ভাষা সংক্রান্ত নিয়ম ব্যবহার করে। এই ক্ষেত্রে TBAA জানে যে একটি ভাসা করতে পারেন ওরফে এবং int- এ এবং লোড দূরে সেরা অনুকূল রূপ আমি

এখন, বিধি-পুস্তকে

মানকটি ঠিক কী বলে যে আমাদের অনুমতি দেওয়া হয় এবং তা করার অনুমতি দেওয়া হয় না? স্ট্যান্ডার্ড ভাষা সোজা নয়, সুতরাং প্রতিটি আইটেমের জন্য আমি কোডের উদাহরণ দেওয়ার চেষ্টা করব যা অর্থটি প্রকাশ করে।

সি 11 স্ট্যান্ডার্ড কী বলে?

C11 মান বিভাগে নিম্নলিখিত বলছেন 6.5 প্রকাশ 7 অনুচ্ছেদ :

একটি অবজেক্টের তার সঞ্চিত মানটি কেবলমাত্র একটি মূল্যবান এক্সপ্রেশন দ্বারা অ্যাক্সেস করতে হবে যার নিম্নলিখিত ধরণের একটি রয়েছে: ৮৮) - কোনও প্রকারের কার্যকর ধরণের সাথে সামঞ্জস্যপূর্ণ,

int x = 1;
int *p = &x;   
printf("%d\n", *p); // *p gives us an lvalue expression of type int which is compatible with int

- বস্তুর কার্যকর ধরণের সাথে সামঞ্জস্যপূর্ণ কোনও ধরণের একটি যোগ্য সংস্করণ,

int x = 1;
const int *p = &x;
printf("%d\n", *p); // *p gives us an lvalue expression of type const int which is compatible with int

- এমন এক ধরণের যা বস্তুর কার্যকর ধরণের সাথে সম্পর্কিত স্বাক্ষরযুক্ত বা স্বাক্ষরযুক্ত প্রকার,

int x = 1;
unsigned int *p = (unsigned int*)&x;
printf("%u\n", *p ); // *p gives us an lvalue expression of type unsigned int which corresponds to 
                     // the effective type of the object

জিসিসি / ঝনঝন একটি এক্সটেনশন রয়েছে এবং এছাড়াও যে বরাদ্দ দেয় স্বাক্ষরবিহীন int- * থেকে int- * যদিও তারা সামঞ্জস্যপূর্ণ ধরনের নয়।

- এমন এক ধরণের যা বস্তুর কার্যকর ধরণের কার্যকর সংস্করণের সাথে সম্পর্কিত স্বাক্ষরযুক্ত বা স্বাক্ষরযুক্ত প্রকার,

int x = 1;
const unsigned int *p = (const unsigned int*)&x;
printf("%u\n", *p ); // *p gives us an lvalue expression of type const unsigned int which is a unsigned type 
                     // that corresponds with to a qualified verison of the effective type of the object

- একটি সামগ্রিক বা ইউনিয়ন প্রকার যা এর সদস্যদের মধ্যে পূর্বোক্ত ধরণের একটিকে অন্তর্ভুক্ত করে (অন্তর্ভুক্ত, পুনরাবৃত্তভাবে, একটি উপশ্রেণী বা অন্তর্ভুক্ত ইউনিয়নের সদস্য সহ), বা

struct foo {
  int x;
};

void foobar( struct foo *fp, int *ip );  // struct foo is an aggregate that includes int among its members so it can
                                         // can alias with *ip

foo f;
foobar( &f, &f.x );

- একটি চরিত্রের ধরণ।

int x = 65;
char *p = (char *)&x;
printf("%c\n", *p );  // *p gives us an lvalue expression of type char which is a character type.
                      // The results are not portable due to endianness issues.

সি ++ 17 খসড়া স্ট্যান্ডার্ড কী বলে

[বেসিক.লভাল] অনুচ্ছেদে 11 অনুচ্ছেদে সি ++ 17 খসড়া মান বলেছেন:

একটি প্রোগ্রাম প্রচেষ্টা নিম্নলিখিত প্রকারের আচরণ অনির্দিষ্ট হয় এক ছাড়া অন্য একটি glvalue মাধ্যমে একটি বস্তুর সংরক্ষিত মান অ্যাক্সেস করতে পারেন: 63 (11.1) - বস্তুর গতিশীল ধরন,

void *p = malloc( sizeof(int) ); // We have allocated storage but not started the lifetime of an object
int *ip = new (p) int{0};        // Placement new changes the dynamic type of the object to int
std::cout << *ip << "\n";        // *ip gives us a glvalue expression of type int which matches the dynamic type 
                                  // of the allocated object

(১১.২) - বস্তুর গতিশীল ধরণের একটি সিভি-যোগ্য সংস্করণ,

int x = 1;
const int *cip = &x;
std::cout << *cip << "\n";  // *cip gives us a glvalue expression of type const int which is a cv-qualified 
                            // version of the dynamic type of x

(১১.৩) - বস্তুর গতিশীল ধরণের সাথে একই ধরণের (.5.৫ সংজ্ঞায়িত),

(১১.৪) - এমন এক ধরণের যা বস্তুর গতিশীল ধরণের সাথে সম্পর্কিত স্বাক্ষরযুক্ত বা স্বাক্ষরযুক্ত প্রকার,

// Both si and ui are signed or unsigned types corresponding to each others dynamic types
// We can see from this godbolt(https://godbolt.org/g/KowGXB) the optimizer assumes aliasing.
signed int foo( signed int &si, unsigned int &ui ) {
  si = 1;
  ui = 2;

  return si;
}

(১১.৫) - এমন এক ধরণের যা বস্তুর গতিশীল প্রকারের সিভি-যোগ্য সংস্করণের সাথে সম্পর্কিত স্বাক্ষরিত বা স্বাক্ষরযুক্ত প্রকার,

signed int foo( const signed int &si1, int &si2); // Hard to show this one assumes aliasing

(১১..6) - একটি সামগ্রিক বা ইউনিয়ন প্রকার যা এর উপাদান বা ননস্ট্যাটিক ডেটা সদস্যদের মধ্যে পূর্ব বর্ণিত ধরণের একটি অন্তর্ভুক্ত করে (অন্তর্ভুক্ত বা সংযুক্ত ইউনিয়নের উপাদান বা অ-স্থিতিশীল ডেটা সদস্য সহ, পুনরাবৃত্তভাবে),

struct foo {
 int x;
};

// Compiler Explorer example(https://godbolt.org/g/z2wJTC) shows aliasing assumption
int foobar( foo &fp, int &ip ) {
 fp.x = 1;
 ip = 2;

 return fp.x;
}

foo f; 
foobar( f, f.x ); 

(১১.7) - এমন এক ধরণের যা (সম্ভবত সিভি-কোয়ালিটিভড) অবজেক্টের ডায়নামিক টাইপের বেস ক্লাস টাইপ,

struct foo { int x ; };

struct bar : public foo {};

int foobar( foo &f, bar &b ) {
  f.x = 1;
  b.x = 2;

  return f.x;
}

(১১.৮) - একটি চর, স্বাক্ষরবিহীন চর, বা স্টাড :: বাইট প্রকার।

int foo( std::byte &b, uint32_t &ui ) {
  b = static_cast<std::byte>('a');
  ui = 0xFFFFFFFF;                   

  return std::to_integer<int>( b );  // b gives us a glvalue expression of type std::byte which can alias
                                     // an object of type uint32_t
}

লক্ষণীয় স্বাক্ষরিত চরটি উপরের তালিকায় অন্তর্ভুক্ত নয়, এটি সি থেকে একটি উল্লেখযোগ্য পার্থক্য যা একটি চরিত্রের ধরণ বলে

টাইপ পেনিং কী

আমরা এই মুহুর্তে পৌঁছেছি এবং আমরা ভাবতে পারি, আমরা কেন তার উপাধি চাইব? উত্তরটি সাধারণত পাং টাইপ করা হয় , প্রায়শই ব্যবহৃত পদ্ধতিগুলি কঠোরভাবে আলিয়াজিং বিধি লঙ্ঘন করে।

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

Ditionতিহ্যগতভাবে এটি সামগ্রীর ঠিকানা গ্রহণ করে, আমরা যে ধরণের পুনরায় ব্যাখ্যা করতে চাই এবং তারপরে মানটি অ্যাক্সেস করতে চাই বা অন্য শব্দে আলিয়াজ করে এটি ব্যবহার করি তার বিন্দুতে কাস্টিংয়ের মাধ্যমে এটি সম্পন্ন হয়েছে। উদাহরণ স্বরূপ:

int x =  1 ;

// In C
float *fp = (float*)&x ;  // Not a valid aliasing

// In C++
float *fp = reinterpret_cast<float*>(&x) ;  // Not a valid aliasing

printf( "%f\n", *fp ) ;

যেমনটি আমরা আগে দেখেছি এটি কোনও বৈধ আলিয়াজিং নয়, তাই আমরা অনির্ধারিত আচরণের জন্য প্রার্থনা করছি। তবে traditionতিহ্যগতভাবে সংকলকগণ কঠোর আলিয়াজিং বিধিগুলির সুবিধা নেন নি এবং সাধারণত এই ধরণের কোডটি কেবলমাত্র কাজ করেছিল, দুর্ভাগ্যক্রমে বিকাশকারীরা জিনিসগুলি এভাবে করায় অভ্যস্ত হয়ে পড়েছে। টাইপ পেনিংয়ের জন্য একটি সাধারণ বিকল্প পদ্ধতিটি ইউনিয়নগুলির মাধ্যমে হয়, যা সিতে বৈধ তবে সি ++ এ অপরিবর্তিত আচরণ ( সরাসরি উদাহরণ দেখুন ):

union u1
{
  int n;
  float f;
} ;

union u1 u;
u.f = 1.0f;

printf( "%d\n”, u.n );  // UB in C++ n is not the active member

এটি সি ++ তে বৈধ নয় এবং কেউ কেউ ইউনিয়নগুলির উদ্দেশ্যটি কেবলমাত্র বৈকল্পিক ধরণের প্রয়োগের জন্য বিবেচনা করে এবং ইউনিয়নগুলি টাইপ পেনিংয়ের জন্য ব্যবহার করা একটি অপব্যবহার বলে মনে করে।

আমরা কীভাবে পুণ টাইপ করব?

সি এবং সি ++ উভয় প্রকারের পাণিংয়ের স্ট্যান্ডার্ড পদ্ধতি হ'ল ম্যাকপি । এটি সামান্য ভারী হাতের মতো মনে হতে পারে তবে অপ্টিমাইজারের উচিত টাইপ পেনিংয়ের জন্য মেমকি ব্যবহার করা উচিত এবং এটি অপ্টিমাইজ করা উচিত এবং সরানো রেজিস্ট্রেশন করার জন্য একটি রেজিস্টার তৈরি করা উচিত। উদাহরণস্বরূপ যদি আমরা জানতে পারি যে int64_t ডাবল হিসাবে একই আকারের হয় :

static_assert( sizeof( double ) == sizeof( int64_t ) );  // C++17 does not require a message

আমরা মেমকি ব্যবহার করতে পারি :

void func1( double d ) {
  std::int64_t n;
  std::memcpy(&n, &d, sizeof d); 
  //...

অবশ্যই যথেষ্ট অপ্টিমাইজেশান স্তরে কোন ভদ্র আধুনিক কম্পাইলার পূর্বে উল্লিখিত অভিন্ন কোড জেনারেট করে reinterpret_cast পদ্ধতি বা ইউনিয়ন জন্য পদ্ধতি টাইপ punning । উত্পন্ন কোড পরীক্ষা করে আমরা দেখতে পাই এটি কেবল রেজিস্টার রেজিস্ট্রেশন ব্যবহার করে ( লাইভ সংকলক এক্সপ্লোরার উদাহরণ )।

সি ++ 20 এবং বিট_কাস্ট

সি ++ ২০-এ আমরা বিট_কাস্ট ( প্রস্তাবের লিঙ্কে উপলব্ধ বাস্তবায়ন ) পেতে পারি যা টাইপ-পুণের একটি সহজ এবং নিরাপদ উপায় দেয় এবং পাশাপাশি কনস্টেক্সপ্রপেক্টে ব্যবহারের যোগ্য হয়।

নিম্নলিখিত কিভাবে ব্যবহার করতে একটি উদাহরণ bit_cast একটি শ্লেষ টাইপ করতে স্বাক্ষরবিহীন int- এ থেকে ভাসা , ( এটা লাইভ দেখতে পাবেন ):

std::cout << bit_cast<float>(0x447a0000) << "\n" ; //assuming sizeof(float) == sizeof(unsigned int)

কেস যেখানে ইন করার এবং থেকে ধরনের একই আকার থাকে না, এটা কোন মধ্যবর্তী struct15 ব্যবহার করতে আমাদের প্রয়োজন। আমরা একটি struct একটি ধারণকারী ব্যবহার করবে যাও sizeof (স্বাক্ষরবিহীন int- এ) চরিত্র অ্যারে ( অনুমান 4 বাইট স্বাক্ষরবিহীন int- এ ) হতে থেকে ধরন ও স্বাক্ষরবিহীন int- এ যেমন করতে টাইপ .:

struct uint_chars {
 unsigned char arr[sizeof( unsigned int )] = {} ;  // Assume sizeof( unsigned int ) == 4
};

// Assume len is a multiple of 4 
int bar( unsigned char *p, size_t len ) {
 int result = 0;

 for( size_t index = 0; index < len; index += sizeof(unsigned int) ) {
   uint_chars f;
   std::memcpy( f.arr, &p[index], sizeof(unsigned int));
   unsigned int result = bit_cast<unsigned int>(f);

   result += foo( result );
 }

 return result ;
}

দুর্ভাগ্যজনক যে আমাদের এই মাঝারি ধরনের প্রয়োজন তবে এটি বিটকাস্টের বর্তমান সীমাবদ্ধতা ।

কঠোর Aliasing লঙ্ঘন ক্যাচিং

সি ++ তে কড়া আলিয়াজিং ধরার জন্য আমাদের কাছে প্রচুর ভাল সরঞ্জাম নেই, আমাদের কাছে যে সরঞ্জামগুলি রয়েছে তা কঠোরভাবে আলিয়াসিং লঙ্ঘনের কয়েকটি মামলা এবং মিসিলাইনযুক্ত লোড এবং স্টোরগুলির কিছু কেস ধরবে।

জি.সি.সি. ফ্ল্যাগ -স্ট্রিট-এলিয়াসিং এবং -স্ট্রিট- এলিয়জিং ব্যবহার করে কিছু মামলা ধরা যেতে পারে যদিও মিথ্যা পজিটিভ / নেগেটিভ ছাড়াই নয়। উদাহরণস্বরূপ, নিম্নলিখিত কেসগুলি জিসিসিতে একটি সতর্কতা উত্পন্ন করবে ( এটি সরাসরি দেখুন ):

int a = 1;
short j;
float f = 1.f; // Originally not initialized but tis-kernel caught 
               // it was being accessed w/ an indeterminate value below

printf("%i\n", j = *(reinterpret_cast<short*>(&a)));
printf("%i\n", j = *(reinterpret_cast<int*>(&f)));

যদিও এটি এই অতিরিক্ত কেসটি ধরবে না ( এটি সরাসরি দেখুন ):

int *p;

p=&a;
printf("%i\n", j = *(reinterpret_cast<short*>(p)));

যদিও ঝাঁকুনি এই পতাকাগুলির অনুমতি দেয় এটি স্পষ্টতই সতর্কতাগুলি প্রয়োগ করে না।

আমাদের কাছে আর একটি সরঞ্জাম উপলব্ধ রয়েছে যেটি হ'ল আসান যা ভুল পথে চালিত লোড এবং স্টোরগুলি ধরতে পারে। যদিও এগুলি সরাসরি কড়া আলিয়াসিং লঙ্ঘন নয় তবে এগুলি কঠোরভাবে এলিয়াসিং লঙ্ঘনের একটি সাধারণ ফলাফল। উদাহরণস্বরূপ যখন -fsanitize = ঠিকানা ব্যবহার করে ঝাঁকুনির সাথে নির্মিত তখন নিম্নলিখিত কেসগুলি রানটাইম ত্রুটি তৈরি করে

int *x = new int[2];               // 8 bytes: [0,7].
int *u = (int*)((char*)x + 6);     // regardless of alignment of x this will not be an aligned address
*u = 1;                            // Access to range [6-9]
printf( "%d\n", *u );              // Access to range [6-9]

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

সি এর জন্য আমাদের কাছে সমস্ত সরঞ্জাম ইতিমধ্যে আচ্ছাদিত রয়েছে এবং আমাদের টিস-ইন্টারপ্রেটারও রয়েছে, একটি স্ট্যাটিক বিশ্লেষক যা সি ভাষার বৃহত উপসেটের জন্য একটি প্রোগ্রামকে নিখরচায় বিশ্লেষণ করে। পূর্ববর্তী উদাহরণের সি ভার্শন দেওয়া যেখানে -স্ট্রিক্ট-এলিয়াসিং ব্যবহার করে একটি কেস মিস হয় ( এটি সরাসরি দেখুন )

int a = 1;
short j;
float f = 1.0 ;

printf("%i\n", j = *((short*)&a));
printf("%i\n", j = *((int*)&f));

int *p; 

p=&a;
printf("%i\n", j = *((short*)p));

টিস-ইন্টারপেটর তিনটিই ধরতে সক্ষম, নিম্নলিখিত উদাহরণটি টিস-কার্নালকে টিআইস-ইন্টারপ্রেটার হিসাবে আহ্বান করে (আউটপুটটি ব্রিভিটির জন্য সম্পাদিত হয়):

./bin/tis-kernel -sa example1.c 
...
example1.c:9:[sa] warning: The pointer (short *)(& a) has type short *. It violates strict aliasing
              rules by accessing a cell with effective type int.
...

example1.c:10:[sa] warning: The pointer (int *)(& f) has type int *. It violates strict aliasing rules by
              accessing a cell with effective type float.
              Callstack: main
...

example1.c:15:[sa] warning: The pointer (short *)p has type short *. It violates strict aliasing rules by
              accessing a cell with effective type int.

অবশেষে টাইসান রয়েছে যা বর্তমানে বিকাশে রয়েছে। এই স্যানিটাইজার একটি ছায়া মেমরি বিভাগে টাইপ চেকিংয়ের তথ্য যুক্ত করে এবং অ্যালাইজিং বিধি লঙ্ঘন করে কিনা তা দেখার জন্য অ্যাক্সেসগুলি পরীক্ষা করে। সরঞ্জামটি সম্ভাব্যভাবে সমস্ত এলিয়াসিং লঙ্ঘন ধরতে সক্ষম হওয়া উচিত তবে এতে একটি বড় রান-টাইম ওভারহেড থাকতে পারে।


মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
Bhargav রাও

3
যদি আমি, +10, উভয় পক্ষের, সংকলক লেখক এবং প্রোগ্রামারদের থেকেও ভালভাবে লিখিত এবং ব্যাখ্যা করতে পারতাম ... তবে একমাত্র সমালোচনা: মানকটি কীভাবে নিষিদ্ধ, তা দেখার জন্য উপরে উল্টো উদাহরণ দেওয়া ভাল লাগবে ধরণের :-)
গ্যাব্রিয়েল

2
খুব ভাল উত্তর। আমি কেবল আফসোস করছি যে প্রাথমিক উদাহরণগুলি সি ++ এ দেওয়া হয়েছে, যা আমার মতো লোকদের অনুসরণ করা কঠিন করে তোলে যারা কেবল সি সম্পর্কে জানেন বা তাদের যত্ন নেন এবং কী reinterpret_castকরতে পারেন বা এর coutঅর্থ কী হতে পারে তা জানেন না। (সি ++ উল্লেখ করা ঠিক আছে তবে মূল প্রশ্নটি সি এবং আইআইইউসি সম্পর্কে ছিল এই উদাহরণগুলি যথাযথভাবে সিটিতে লেখা যেতে পারে)
গ্রো-তসেন

টাইপ পেনিং সম্পর্কিত: সুতরাং যদি আমি কোনও ধরণের এক্সের ফাইলে ফাইলে লিখি, তবে সেই ফাইলটি থেকে এই অ্যারেটি মেমোরিতে অকার্যকর * দিয়ে পড়ুন, তারপরে আমি সেই পয়েন্টারটিকে ব্যবহারের জন্য তথ্যটির প্রকৃত প্রকারের মধ্যে ফেলেছি - এটাই অপরিবর্তিত আচরণ?
মাইকেল চতুর্থ

44

কঠোর আলিয়াজিং কেবল পয়েন্টারগুলিকেই উল্লেখ করে না, এটি রেফারেন্সগুলিকেও প্রভাবিত করে, আমি এটি সম্পর্কে একটি বিকাশকারী বিকাশকারী উইকিটির জন্য একটি কাগজ লিখেছিলাম এবং এটি এত ভালভাবে গৃহীত হয়েছিল যে আমি এটিকে আমার পরামর্শ ওয়েবসাইটের একটি পৃষ্ঠায় পরিণত করেছি। এটি সম্পূর্ণরূপে ব্যাখ্যা করে যে এটি কী, এটি কেন মানুষকে এত বিভ্রান্ত করে এবং এটি সম্পর্কে কী করা উচিত। স্ট্রাইক আলিয়াসিং হোয়াইট পেপার । বিশেষত এটি ব্যাখ্যা করে যে ইউনিয়নগুলি কেন সি ++ এর জন্য ঝুঁকিপূর্ণ আচরণ, এবং মেমকি ব্যবহার কেন সি এবং সি ++ উভয়ই একমাত্র স্থিরযোগ্য পোর্টেবল। আশা করি এটি সহায়ক।


3
" কঠোর আলিয়াসিং কেবল পয়েন্টারগুলিকেই উল্লেখ করে না, এটি রেফারেন্সগুলিকেও প্রভাবিত করে " প্রকৃতপক্ষে, এটি লভ্যগুলিকে বোঝায় । " মেমকি ব্যবহার করা একমাত্র স্থিরযোগ্য পোর্টেবল " শুনুন!
কৌতূহলী

5
ভাল কাগজ। আমার গ্রহণ: (১) এই এলিয়াসিং-'প্রব্লেম 'খারাপ প্রোগ্রামিংয়ের একটি অতিরিক্ত প্রতিক্রিয়া - খারাপ প্রোগ্রামারকে তার খারাপ অভ্যাস থেকে রক্ষা করার চেষ্টা করে। প্রোগ্রামারটির যদি ভাল অভ্যাস থাকে তবে এই এলিয়াসিংটি কেবল একটি উপদ্রব এবং চেকগুলি নিরাপদে বন্ধ করা যেতে পারে। (২) সংকলক-পক্ষের অপ্টিমাইজেশন কেবল সুপরিচিত ক্ষেত্রেই করা উচিত এবং সন্দেহের ভিত্তিতে উত্স-কোডটি কঠোরভাবে অনুসরণ করা উচিত; সংস্থাপকের আইডিসিএনক্র্যাসিগুলি পূরণের জন্য প্রোগ্রামারকে কোড লিখতে বাধ্য করা, সহজভাবে বলা যায় ভুল wrong এমনকি এটি স্ট্যান্ডার্ডের অংশ করা আরও খারাপ।
স্ল্যাশমায়াই

4
@ স্ল্যাশমাইস (1) " বাজে প্রোগ্রামিংয়ের একটি অতিরিক্ত প্রতিক্রিয়া " ননসেন্স sen এটি খারাপ অভ্যাসের প্রত্যাখ্যান। তুমি এটা করো? আপনি মূল্য পরিশোধ করুন: আপনার জন্য কোনও গ্যারান্টি নেই! (২) সুপরিচিত কেস? কোনটা? কঠোর আলিয়াজিংয়ের নিয়মটি "সুপরিচিত" হওয়া উচিত!
কৌতূহলী

5
@ কুরিয়াসগুয়ে: বিভ্রান্তির কয়েকটি বিষয় পরিষ্কার করার পরে, এটি স্পষ্ট যে এলিয়াসিং বিধিগুলির সাথে সি ভাষা প্রোগ্রামগুলিকে টাইপ-অজোনস্টিক মেমরি পুলগুলি বাস্তবায়ন করা অসম্ভব করে তোলে। কিছু ধরণের প্রোগ্রাম ম্যালোক / ফ্রি সহ পেতে পারে তবে অন্যদের হাতে থাকা কাজের সাথে তাল মিলিয়ে মেমরি পরিচালনার যুক্তি প্রয়োজন better আমি অবাক হই যে কেন সি 89 এর যুক্তি এলিয়াসিং রুলের কারণের জন্য এইরকম কুটিল উদাহরণ ব্যবহার করেছিল, যেহেতু তাদের উদাহরণটি দেখে মনে হয় যে এই নিয়মটি কোনও যুক্তিসঙ্গত কাজ সম্পাদনে কোনও বড় অসুবিধা করবে না।
1515

5
@ কুরিয়াসগুয়ে, বেশিরভাগ সংকলক স্যুট -O3-তে ডিফল্ট হিসাবে-স্ট্রাক্ট-এলিয়াসিং অন্তর্ভুক্ত রয়েছে এবং এই লুকানো চুক্তিটি ব্যবহারকারীদের উপর জোর করা হয়েছে যারা কখনও টিবিএএ শুনে নি এবং কোনও সিস্টেম প্রোগ্রামার কীভাবে পারে তার মতো কোড লিখেছিল। আমি সিস্টেম প্রোগ্রামারদের কাছে স্বতন্ত্র শব্দ বলতে চাইছি না, তবে এই ধরণের অপ্টিমাইজেশানটি -O3 এর ডিফল্ট অপ্টের বাইরে ছেড়ে যাওয়া উচিত এবং যারা টিবিএএ জানেন তাদের জন্য একটি অপ্ট-ইন অপ্টিমাইজেশন হওয়া উচিত। সংকলক 'বাগ' দেখে মজা পাওয়া যায় না যা টিবিএএ লঙ্ঘনকারী ব্যবহারকারী কোড হিসাবে দেখা যায়, বিশেষত ব্যবহারকারীর কোডে উত্স স্তরের লঙ্ঘন সন্ধান করে।
কেচোই

34

ডগ টি ইতিমধ্যে যা লিখেছিল তার সংযোজন হিসাবে, এখানে একটি সাধারণ পরীক্ষার কেস যা সম্ভবত এটি জিসিসি দিয়ে ট্রিগার করে:

check.c

#include <stdio.h>

void check(short *h,long *k)
{
    *h=5;
    *k=6;
    if (*h == 5)
        printf("strict aliasing problem\n");
}

int main(void)
{
    long      k[1];
    check((short *)k,k);
    return 0;
}

সংকলন gcc -O2 -o check check.c। সাধারণত (বেশিরভাগ জিসিসি সংস্করণ সহ আমি চেষ্টা করেছি) এই ফলাফলটি "কঠোর আলিয়াজিং সমস্যা" হয়, কারণ সংকলক ধরে নিয়েছে যে "এইচ" "চেক" ফাংশনে "কে" এর মতো ঠিকানা হতে পারে না। যে কারণে সংকলক if (*h == 5)দূরে অপ্টিমাইজ করে এবং সর্বদা প্রিন্টফকে কল করে।

যারা এখানে আগ্রহী তাদের জন্য x64 এসেম্বলারের কোড, জিসিসি 4.6.3 দ্বারা উত্পাদিত, এক্স 64 এর জন্য উবুন্টু 12.04.2 এ চলছে:

movw    $5, (%rdi)
movq    $6, (%rsi)
movl    $.LC0, %edi
jmp puts

সুতরাং যদি শর্তটি পুরোপুরি এসেম্বেলার কোড থেকে চলে যায়।


যদি আপনি দ্বিতীয় সংক্ষিপ্ত * জে যোগ করেন () যাচাই করুন এবং এটি ব্যবহার করুন (* জে = 7) তবে অপ্টিমাইজেশন অদৃশ্য হয়ে যাবে যেহেতু জিজিসি যদি হ'ল এবং জে একই মানের প্রকৃতপক্ষে বিন্দু না হয় তবে তা হয় না। হ্যাঁ অপ্টিমাইজেশন সত্যিই স্মার্ট।
ফিলিপ্পে লার্ডি

2
জিনিসগুলিকে আরও মজাদার করতে, এমন ধরণের পয়েন্টার ব্যবহার করুন যা সামঞ্জস্যপূর্ণ নয় তবে একই আকার এবং উপস্থাপনা (কিছু সিস্টেমে যা সত্য long long*এবং int64_t* এর সত্য )। এক আশা করতে পারে যে একটি বিবেকী কম্পাইলার স্বীকার করা উচিত যে একটি long long*এবং int64_t*একই স্টোরেজ যদি তারা অভিন্নরুপে সঞ্চিত অ্যাক্সেস করতে পারে, কিন্তু এই ধরনের চিকিত্সা কেতাদুরস্ত এখন আর নেই।
সুপারক্যাট

গ্রার ... x64 একটি মাইক্রোসফ্ট কনভেনশন। পরিবর্তে amd64 বা x86_64 ব্যবহার করুন।
এসএস অ্যান

গ্রার ... x64 একটি মাইক্রোসফ্ট কনভেনশন। পরিবর্তে amd64 বা x86_64 ব্যবহার করুন।
এসএস অ্যান

17

পয়েন্টার কাস্টের মাধ্যমে টাইপ পেনিং (ইউনিয়ন ব্যবহারের বিপরীতে) কঠোর আলিয়াজিং ভাঙার একটি বড় উদাহরণ।


1
প্রাসঙ্গিক উক্তিগুলির জন্য আমার উত্তরটি এখানে দেখুন , বিশেষত পাদটীকা কিন্তু ইউনিয়নগুলির মাধ্যমে টাইপ পেনিং দেওয়ার বিষয়টি সর্বদা সিতে অনুমোদিত হয়েছে যদিও প্রথমে এটি খারাপভাবে বলা হয়েছিল। আপনি আমার উত্তর পরিষ্কার করতে চান।
শফিক ইয়াঘমোর

@ শফিকিক ইয়াঘমুর: সি ৯৯ কার্যকরভাবে ইউনিয়নগুলির মাধ্যমে টাইপ পাঞ্জিংকে স্বীকৃতি দেবে বা করবে না এমন মামলাগুলি নির্বাচন করার জন্য স্পষ্টভাবে অনুমতি দিয়েছে। উদাহরণস্বরূপ, একটি প্রয়োগকারী নির্দিষ্ট করে লিখতে পারে যে কোনও ধরণের লেখার পরে অন্যের পাঠ্য টাইপ পেনিং হিসাবে স্বীকৃতি পেতে পারে, যদি প্রোগ্রামার লেখার এবং পঠনের মধ্যে নিম্নলিখিতগুলির মধ্যে দুটি করে থাকে : (1) সমষ্টিযুক্ত একটি মূল্যকে মূল্যায়ন করতে পারে ইউনিয়ন প্রকারের [সদস্যের ঠিকানা নেওয়া যোগ্য হবে, যদি ক্রমের ডান পয়েন্টে করা হয়]; (২) পয়েন্টারকে এক প্রকারে অন্য প্রান্তে রূপান্তর করুন এবং সেই পিটিআর দিয়ে অ্যাক্সেস করুন।
সুপারক্যাট

@ শফিকিক ইয়াঘমুর: একটি বাস্তবায়ন উল্লেখ করতে পারে উদাহরণস্বরূপ, পূর্ণসংখ্যা এবং ভাসমান-পয়েন্টের মানগুলির মধ্যে এই ধরণের শাস্তি কেবল তখনই নির্ভরযোগ্যভাবে কাজ করতে পারে যদি কোড fpsync()এফপি হিসাবে লেখার এবং ইন্ট বা বিপরীতভাবে পড়ার মধ্যে [পৃথক পূর্ণসংখ্যার এবং এফপিইউ পাইপলাইন এবং ক্যাশের সাথে বাস্তবায়নের ক্ষেত্রে কার্যকর হয় code , এই জাতীয় নির্দেশিকা ব্যয়বহুল হতে পারে, তবে প্রতিটি ইউনিয়ন অ্যাক্সেসে সংকলকটি এ জাতীয় সিঙ্ক্রোনাইজেশন সম্পাদনের মতো ব্যয়বহুল নয়]। বা কোনও বাস্তবায়ন নির্দিষ্ট করে দিতে পারে যে সাধারণ প্রাথমিক সিকোয়েন্সগুলি ব্যবহার করে ফলাফল ছাড়া ফলাফল কখনই ব্যবহারযোগ্য হবে না।
সুপারক্যাট

@ShafikYaghmour: C89 অধীনে, বাস্তবায়নের পারে টাইপ punning অধিকাংশ ফর্ম, ইউনিয়ন মাধ্যমে সহ, কিন্তু ইউনিয়ন ও তাদের সদস্যদের ইঙ্গিত দিয়েছিল যে, টাইপ punning বাস্তবায়নের যে করা হয়নি এ অনুমতি দেওয়া হয়েছিল পয়েন্টার পয়েন্টার মধ্যে সমানতা নিষেধ স্পষ্টভাবে এটা নিষেধ।
সুপারক্যাট

17

সি 89 এর যুক্তি অনুসারে, স্ট্যান্ডার্ডের লেখকরা এই সংকলকদের কোডের মতো কোডের প্রয়োজন পড়েনি:

int x;
int test(double *p)
{
  x=5;
  *p = 1.0;
  return x;
}

মান পুনরায় লোড করা প্রয়োজন হবে xনিয়োগ এবং বিনিময়ে বিবৃতি মধ্যে, যাতে সম্ভাবনা জন্য অনুমতি pশক্তি বিন্দু x, এবং নিয়োগ *pশক্তি পরিণামে মান পরিবর্তন x। কোনও সংকলক উপরের মতো পরিস্থিতিতে এলিয়াস হবে না এমন ধারণা করার অধিকারী হওয়া উচিত এই ধারণাটি বিতর্কিত ছিল না।

দুর্ভাগ্যক্রমে, সি 89 এর লেখকরা তাদের নিয়মটি এমনভাবে লিখেছিলেন যে, যদি আক্ষরিক অর্থে পাঠ করা হয় তবে নীচের ফাংশনটি এমনকি অনির্ধারিত আচরণকেও আহ্বান জানায়:

void test(void)
{
  struct S {int x;} s;
  s.x = 1;
}

কারণ এটি কোনও ধরণের intঅবজেক্টটিতে অ্যাক্সেস পেতে টাইপের একটি লভ্যালু ব্যবহার করে struct Sএবং intএটি অ্যাক্সেস ব্যবহার করে এমন ধরণের মধ্যে নয় struct S। যেহেতু স্ট্রাক্ট এবং ইউনিয়নগুলির অ-চরিত্র-ধরণের সদস্যদের সমস্ত ব্যবহারকে অপরিজ্ঞাত আচরণ হিসাবে বিবেচনা করা অযৌক্তিক হবে, প্রায় প্রত্যেকেই স্বীকার করেছেন যে কমপক্ষে এমন কিছু পরিস্থিতিতে রয়েছে যেখানে অন্য ধরণের কোনও অবজেক্ট অ্যাক্সেস করার জন্য এক ধরণের লভ্যালু ব্যবহার করা যেতে পারে । দুর্ভাগ্যক্রমে, সি স্ট্যান্ডার্ড কমিটি এই পরিস্থিতিতে কী তা নির্ধারণ করতে ব্যর্থ হয়েছে।

বেশিরভাগ সমস্যা হ'ল ত্রুটি প্রতিবেদন # 028 এর ফলাফল, যা এই জাতীয় প্রোগ্রামের আচরণ সম্পর্কে জিজ্ঞাসা করেছিল:

int test(int *ip, double *dp)
{
  *ip = 1;
  *dp = 1.23;
  return *ip;
}
int test2(void)
{
  union U { int i; double d; } u;
  return test(&u.i, &u.d);
}

ত্রুটি প্রতিবেদন # 28 তে উল্লেখ করা হয়েছে যে প্রোগ্রামটি "ডাবল" টাইপের ইউনিয়ন সদস্যকে লেখার এবং "ইনট" টাইপের কোনও একটি পড়ার ক্রমটি বাস্তবায়ন-সংজ্ঞায়িত আচরণকে আহ্বান করে। এ জাতীয় যুক্তি অযৌক্তিক, তবে কার্যকর ধরণের নিয়মের ভিত্তি তৈরি করে যা মূল সমস্যাটি সমাধান করার জন্য কিছুই না করে অযথা ভাষা জটিল করে তোলে।

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

 void inc_int(int *p) { *p = 3; }
 int test(void)
 {
   int *p;
   struct S { int x; } s;
   s.x = 1;
   p = &s.x;
   inc_int(p);
   return s.x;
 }

এর মধ্যে কোনও বিরোধ নেই inc_intকারণ *pস্টোরেজটিতে অ্যাক্সেস করা সমস্ত অ্যাক্সেসগুলি ধরণের লভ্য দিয়ে সম্পন্ন হয় intএবং এতে কোনও বিরোধ নেই testকারণ pদৃশ্যমান একটি থেকে উদ্ভূত struct Sহয় এবং পরবর্তী সময় sব্যবহার করা হয়, সেই স্টোরেজে সমস্ত প্রবেশাধিকার যা কখনও তৈরি হবে will pইতিমধ্যে ঘটেছে মাধ্যমে ।

কোডটি যদি কিছুটা পরিবর্তন করা হয় ...

 void inc_int(int *p) { *p = 3; }
 int test(void)
 {
   int *p;
   struct S { int x; } s;
   p = &s.x;
   s.x = 1;  //  !!*!!
   *p += 1;
   return s.x;
 }

এখানে, চিহ্নিত লাইনে pঅ্যাক্সেসের মধ্যে একটি এলিয়াসিং দ্বন্দ্ব রয়েছে s.xকারণ মৃত্যুর সময় সেই একই সময়ে অন্য রেফারেন্স উপস্থিত রয়েছে যা একই স্টোরেজ অ্যাক্সেস করতে ব্যবহৃত হবে

হ্যাড ডিফেক্ট রিপোর্ট 028 বলেছিল যে দুটি উদাহরণের তৈরি এবং ব্যবহারের মধ্যে ওভারল্যাপের কারণে মূল উদাহরণটি ইউবিকে ডেকেছে, এটি "কার্যকর ধরণের" বা এই জাতীয় জটিলতা যুক্ত না করে বিষয়গুলিকে অনেক বেশি পরিষ্কার করে দিত।


ভাল কথা বলতে গেলে, এমন ধরণের একটি প্রস্তাবটি পড়তে আগ্রহী হবে যা কমবেশি "স্ট্যান্ডার্ড কমিটি কী করতে পারে" যা এতটা জটিলতার পরিচয় না দিয়ে তাদের লক্ষ্য অর্জন করেছিল।
jrh

1
@ জিরহ: আমার ধারণা এটি খুব সহজ হবে। সনাক্ত করুন যে ১. কোনও ফাংশন বা লুপের নির্দিষ্ট মৃত্যুর সময় অ্যালিজিংয়ের জন্য, এই কার্যকর করার সময় দুটি পৃথক পয়েন্টার বা ল্যাভ্যুগুলি অবশ্যই কার্যকর করতে হবে বিরোধী ফ্যাশনে একই স্টোরেজটিকে সম্বোধন করার জন্য; ২. চিহ্নিত করুন যে প্রসঙ্গে যেখানে একটি পয়েন্টার বা লভালু অন্যটি থেকে স্বতঃস্ফূর্তভাবে উদ্ভূত হয়, সেখানে দ্বিতীয়টিতে অ্যাক্সেস প্রথমটির প্রবেশাধিকার; ৩. স্বীকৃতি জানুন যে নিয়মটি এমন ক্ষেত্রে প্রয়োগ করার উদ্দেশ্যে নয় যা প্রকৃতপক্ষে এলিয়াসিংয়ের সাথে জড়িত না।
সুপারক্যাট

1
সংকলকটি সতেজ-উদ্ভূত লভ্যালুকে স্বীকৃতি দেয় ঠিক সেই পরিস্থিতিগুলি কোয়ালিটি অফ অফ ইমপ্লিমেন্টেশন ইস্যু হতে পারে তবে যে কোনও দূরবর্তী-শালীন সংকলক জিসিসি এবং জঞ্জাল ইচ্ছাকৃতভাবে উপেক্ষা করা ফর্মগুলি সনাক্ত করতে সক্ষম হবে।
সুপারক্যাট

11

অনেক উত্তর পড়ার পরে, আমি কিছু যুক্ত করার প্রয়োজনীয়তা অনুভব করছি:

কঠোর আলিয়াজিং (যা আমি কিছুক্ষণের মধ্যে বর্ণনা করব) গুরুত্বপূর্ণ কারণ :

  1. মেমোরি অ্যাক্সেস ব্যয়বহুল (পারফরম্যান্স ওয়াইস) হতে পারে, এজন্য শারীরিক স্মৃতিতে আবার লেখার আগে সিপিইউ রেজিস্টারগুলিতে ডেটা ম্যানিপুলেট করা হয়

  2. যদি দুটি পৃথক সিপিইউ রেজিস্টারগুলিতে ডেটা একই মেমরি স্পেসে লেখা থাকে, আমরা সিটি কোড দিলে কোন ডেটা "বেঁচে থাকবে" তা অনুমান করতে পারি না we

    সমাবেশে, যেখানে আমরা ম্যানুয়ালি সিপিইউ নিবন্ধগুলি লোডিং এবং আনলোডিং কোড করি, আমরা জানব কোন ডেটা অক্ষত রয়েছে। তবে সি (কৃতজ্ঞতার সাথে) এই বিবরণটি দূরে রেখে দেয়।

যেহেতু দুটি পয়েন্টার স্মৃতিতে একই অবস্থানকে নির্দেশ করতে পারে, এর ফলে জটিল কোড হতে পারে যা সম্ভাব্য সংঘর্ষগুলি পরিচালনা করে

এই অতিরিক্ত কোডটি ধীর এবং পারফরম্যান্সকে ব্যথা দেয় কারণ এটি অতিরিক্ত মেমরি রিড / রাইটিং অপারেশন করে যা ধীরে ধীরে এবং (সম্ভবত) অপ্রয়োজনীয়।

কঠোর এলিয়াসিং নিয়ম আমাদের অপ্রয়োজনীয় মেশিন কোড এড়াতে পারবেন মামলা যেখানে এটি মধ্যে হওয়া উচিত অনুমান করা যে দুটি পয়েন্টার একই মেমরি ব্লক নির্দেশ করে না নিরাপদ (এছাড়াও দেখুন restrictশব্দ)।

স্ট্রাইক এলিয়াসিং এটি বলে মনে করে নিরাপদ যে বিভিন্ন ধরণের পয়েন্টারগুলি মেমরির বিভিন্ন স্থানে নির্দেশ করে।

কোনও সংকলক যদি লক্ষ্য করে যে দুটি পয়েন্টার বিভিন্ন ধরণের (উদাহরণস্বরূপ, একটি int *এবং ক float *) নির্দেশ করে তবে এটি মেমরি ঠিকানাটি পৃথক বলে ধরে নেবে এবং এটি মেশিনের ঠিকানা সংঘর্ষের বিরুদ্ধে রক্ষা করবে না , যার ফলে দ্রুত মেশিন কোড হয়।

উদাহরণস্বরূপ :

নিম্নলিখিত ফাংশন ধরে নেওয়া যাক:

void merge_two_ints(int *a, int *b) {
  *b += *a;
  *a += *b;
}

কেসটি পরিচালনা করার জন্য a == b(উভয় পয়েন্টার একই মেমোরিটির দিকে নির্দেশ করে), আমাদের সিপিইউ রেজিস্টারগুলিতে মেমরি থেকে ডেটা লোড করার উপায়টি অর্ডার করে পরীক্ষা করতে হবে, যাতে কোডটি এইভাবে শেষ হতে পারে:

  1. লোড aএবং bমেমরি থেকে।

  2. যোগ aকরুন b

  3. সংরক্ষণ b এবং পুনরায় লোড করুন a

    (সিপিইউ রেজিস্টার থেকে মেমরিতে সংরক্ষণ করুন এবং মেমরি থেকে সিপিইউ রেজিস্টারে লোড করুন)।

  4. যোগ bকরুন a

  5. aমেমোরিতে (সিপিইউ রেজিস্টার থেকে) সংরক্ষণ করুন ।

পদক্ষেপ 3 খুব ধীর কারণ এটি শারীরিক স্মৃতি অ্যাক্সেস প্রয়োজন। যাইহোক, এটা দৃষ্টান্ত যেখানে রক্ষা করার জন্য এর প্রয়োজন aএবং bএকই মেমরির ঠিকানায় বিন্দু।

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

  1. এটি দুটি উপায় নির্দেশককে বিভিন্ন ধরণের নির্দেশ করে বলা যেতে পারে। অর্থাৎ,

    void merge_two_numbers(int *a, long *b) {...}
  2. restrictকীওয়ার্ড ব্যবহার করে । অর্থাৎ,

    void merge_two_ints(int * restrict a, int * restrict b) {...}

এখন, কঠোর আলিয়াজিং বিধিটিকে সন্তুষ্ট করে, পদক্ষেপ 3 এড়ানো যায় এবং কোডটি উল্লেখযোগ্যভাবে দ্রুত চলবে।

আসলে, restrictকীওয়ার্ডটি যুক্ত করে পুরো ফাংশনটি এতে অনুকূলিত করা যায়:

  1. লোড aএবং bমেমরি থেকে।

  2. যোগ aকরুন b

  3. aএবং উভয়ই ফলাফল সংরক্ষণ করুন b

সম্ভাব্য সংঘর্ষের কারণে (যেখানে aএবং bদ্বিগুণ হওয়ার পরিবর্তে তিনগুণ হবে) এর আগে এই অপ্টিমাইজেশনটি করা যায়নি ।


সীমাবদ্ধ কীওয়ার্ড সহ, পদক্ষেপ 3 এ, কেবলমাত্র 'বি'-এর ফলাফল সংরক্ষণ করা উচিত নয়? মনে হচ্ছে যেন যোগফলের ফলাফলটি 'ক' তেও সংরক্ষণ করা হবে। এটি কি 'বি' আবার লোড করা প্রয়োজন?
নীলবি

1
@ নীলবি - ইয়াপ আপনি ঠিক বলেছেন। আমরা কেবল সংরক্ষণ করছি b(এটিকে পুনরায় লোড করছি না) এবং পুনরায় লোড করছি a। আমি আশা করি এটি এখন আরও পরিষ্কার হয়ে গেছে।
মাইস্ট

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

মনে রাখবেন যে মূল র‍্যাম থেকে লোড করা খুব ধীর (যদিও নিম্নলিখিত ক্রিয়াকলাপগুলি ফলাফলের উপর নির্ভর করে যদি দীর্ঘ সময়ের জন্য সিপিইউ কোরটি স্টল করতে পারে), এল 1 ক্যাশে থেকে লোড করা খুব দ্রুত, এবং তাই একটি ক্যাশে লাইনে লেখা হচ্ছে যা সম্প্রতি লিখেছিল একই কোর দ্বারা। সুতরাং কোনও ঠিকানাতে প্রথম পড়া বা লেখার বাইরে থাকা সমস্ত কিছু সাধারণত যুক্তিযুক্তভাবে দ্রুত হবে: রেগ / মেমি অ্যাড্রেস অ্যাক্সেসের মধ্যে পার্থক্য ক্যাশেড / অবিবাহিত মেম অ্যাডারের পার্থক্যের চেয়ে ছোট।
কৌতূহলী

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

6

কঠোর আলিয়াসিং একই পাতায় বিভিন্ন পয়েন্টার প্রকারের অনুমতি দিচ্ছে না।

এই নিবন্ধটি আপনাকে পুরো বিশদে বিষয়টি বুঝতে সহায়তা করবে।


4
আপনি রেফারেন্সের মধ্যে এবং একটি রেফারেন্স এবং একটি পয়েন্টারের মধ্যেও উপন্যাস করতে পারেন। আমার টিউটোরিয়ালটি দেখুন dbp-consulting.com
ফোরগান 1

4
একই ডেটাতে বিভিন্ন পয়েন্টার ধরণের অনুমতি রয়েছে। যখন একই মেমরি অবস্থানটি একটি পয়েন্টার টাইপের মাধ্যমে লিখিত হয় এবং অন্যটির মাধ্যমে পড়ে থাকে তখন কঠোর এলিয়াসিং হয়। এছাড়াও, কিছু বিভিন্ন ধরণের অনুমোদিত (যেমন intএবং একটি স্ট্রাক্ট যা একটি রয়েছে int)।
এমএম

-3

প্রযুক্তিগতভাবে সি ++ এ, কঠোর আলিয়াজিং বিধি সম্ভবত কখনও প্রযোজ্য নয়।

ইন্ডিয়ারেশনের সংজ্ঞাটি ( * অপারেটর ) নোট করুন :

ইউনারী * অপারেটর সঞ্চালিত অপ্রত্যক্ষ্যতার: অভিব্যক্তি যা তা প্রয়োগ করা একটি বস্তু টাইপ একটি পয়েন্টার, অথবা একটি ফাংশন টাইপ একটি পয়েন্টার হইবেন এবং ফলাফলের একটি lvalue বস্তুর উল্লেখ করা হয় বা ফাংশন যা অভিব্যক্তি পয়েন্ট

আঠালো সংজ্ঞা থেকে

একটি আঠালো এমন একটি অভিব্যক্তি যার মূল্যায়ন কোনও বস্তুর পরিচয় নির্ধারণ করে, (... স্নিপ)

সুতরাং যে কোনও সংজ্ঞায়িত প্রোগ্রামের ট্রেসগুলিতে, একটি গ্লাভ্যু একটি অবজেক্টকে বোঝায়। সুতরাং তথাকথিত কঠোর aliasing নিয়ম প্রয়োগ হয় না, কখনও। ডিজাইনাররা যা চেয়েছিলেন এটি হতে পারে না।


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

@ সুপের্যাট ভুল। আপনার কল্পনা সত্ত্বেও, এটি আসলে মোটামুটি সামঞ্জস্যপূর্ণ। আইএসও সি-তে এটি "কার্যকরকরণের পরিবেশে ডেটা স্টোরেজের অঞ্চল হিসাবে সংজ্ঞায়িত করা হয়েছে, এর বিষয়বস্তুতে মানগুলি উপস্থাপন করতে পারে"। আইএসও সি ++ তেও একই ধরণের সংজ্ঞা রয়েছে। আপনার মন্তব্য এমনকি উত্তর চেয়ে বেশি অপ্রাসঙ্গিক কারণ সব উল্লেখ করেছে এর উপায় আছে উপস্থাপনা বস্তু 'উল্লেখ করতে বিষয়বস্তু যখন উত্তর প্রকাশ এক্সপ্রেশন এক ধরনের যে শক্তভাবে সম্পর্কিত এর সি ++ ধারণা (glvalue), পরিচয় বস্তুর। এবং সমস্ত এলিয়াসিং নিয়ম মূলত পরিচয়ের সাথে প্রাসঙ্গিক তবে সামগ্রী নয়।
ফ্র্যাঙ্কএইচবি

1
@ ফ্র্যাঙ্কএইচবি: যদি কেউ ঘোষণা করে int foo;, ল্যাভেলু এক্সপ্রেশন দ্বারা কী অ্যাক্সেস করা যায় *(char*)&foo? এটি কি কোনও ধরণের জিনিস char? সেই বস্তুটি কি একই সাথে অস্তিত্বে আসে foo? লিখিতরূপে fooসেই ধরণের পূর্বোক্ত বস্তুর সঞ্চিত মান পরিবর্তন করতে হবে char? যদি তাই হয়, এমন কোনও নিয়ম রয়েছে যা ধরণের charকোনও অবলম্বনের সাহায্যে টাইপের কোনও অবজেক্টের সঞ্চিত মান অ্যাক্সেস করার অনুমতি দেয় int?
সুপারক্যাট

@ ফ্র্যাঙ্কএইচবি: .5.৫ পি of এর অনুপস্থিতিতে, কেউ সহজেই বলতে পারেন যে স্টোরেজের প্রতিটি অঞ্চলে একই সাথে সমস্ত ধরণের সমস্ত অবজেক্ট থাকে যা স্টোরেজের সেই অঞ্চলে মানানসই হতে পারে, এবং যে স্টোরেজ অঞ্চলে অ্যাক্সেস একই সাথে সেগুলি সমস্তকে অ্যাক্সেস করে। এই জাতীয় ফ্যাশনে ব্যাখ্যা করে object.৫ পি "তে" অবজেক্ট "শব্দটি ব্যবহার করা, তবে চরিত্রহীন-ধরণের লভ্যগুলির সাথে অনেক কিছুই করা নিষেধ করবে, এটি স্পষ্টতই একটি অযৌক্তিক ফলাফল হবে এবং নিয়মের উদ্দেশ্যকে সম্পূর্ণ পরাস্ত করবে। তদ্ব্যতীত, 6.5p6 ব্যতীত অন্য কোথাও ব্যবহৃত "অবজেক্ট" ধারণার একটি স্থির সংকলন-টাইপ টাইপ রয়েছে, তবে ...
সুপারক্যাট

1
মাপের (int) 4, ঘোষণাপত্রে int i;প্রতিটি অক্ষরের in addition to one of type int ? I see no way to apply a consistent definition of "object" which would allow for operations on both * (চর *) এবং i` এবং i। এর চারটি অবজেক্ট তৈরি হয় । অবশেষে, স্ট্যান্ডার্ডের এমন কিছুই নেই যা এমন কোনও volatileযোগ্য পয়েন্টারকে হার্ডওয়্যার রেজিস্টারগুলিতে অ্যাক্সেস করার অনুমতি দেয় যা "অবজেক্ট" এর সংজ্ঞা পূরণ করে না।
সুপারক্যাট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.