সি + এর সমমানের :: সি ++ থেকে কম কি?


26

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

সি কি অনুরূপ কার্যকারিতা সহ এমন কিছু প্রস্তাব দেয় যা স্বেচ্ছাসেবী পয়েন্টার (একই ধরণের) নিরাপদে তুলনা করতে দেয়? আমি সি 11 মানদণ্ডটি সন্ধান করার চেষ্টা করেছি এবং কিছুই পাইনি, তবে সি-তে আমার অভিজ্ঞতা হল সি ++ এর চেয়ে ছোট মাত্রার অর্ডার, যাতে আমি সহজেই কিছু মিস করতে পারি।


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

উত্তর:


20

ফ্ল্যাট মেমরির মডেল (মূলত সবকিছু) সহ বাস্তবায়নের সময় uintptr_tউইল জাস্ট ওয়ার্কে castালাই।

(তবে দেখুন পয়েন্টারের তুলনা কি স্বাক্ষরিত হবে বা স্বাক্ষরিত হবে না discussion৪- বিট x86 এ? আলোচনার জন্য আপনার পয়েন্টারকে স্বাক্ষর হিসাবে বিবেচনা করা উচিত কি না, সি এর সাথে ইউবি হওয়া অবজেক্টের বাইরে পয়েন্টার গঠনের বিষয়টি সহ)

কিন্তু অ ফ্ল্যাট মেমরির মডেলের সঙ্গে ব্যবস্থা রয়েছে, এবং তাদের সম্পর্কে চিন্তা সাহায্য করতে পারেন বর্তমান পরিস্থিতি ব্যাখ্যা C- এর মতো ++, জন্য বিভিন্ন চশমা থাকার <বনাম std::less


<সি-তে ইউবি হওয়ার কারণে পৃথক পৃথক বস্তুগুলিতে পয়েন্টার অব পয়েন্ট অব দ্য পয়েন্টের অংশ (বা কিছু সি ++ রিভিশনগুলিতে কমপক্ষে অনির্ধারিত) অ-ফ্ল্যাট মেমরি মডেলগুলি সহ অদ্ভুত মেশিনগুলির জন্য অনুমতি দেওয়া।

অফসেট, ঠিকানা রৈখিক 20-বিট মাধ্যমে বিরচন: একটি সুপরিচিত উদাহরণ x86-16 বাস্তব মোড যেখানে পয়েন্টার সেগমেন্ট হয় (segment << 4) + offset। একই লিনিয়ার ঠিকানাটি একাধিক বিভিন্ন সেগ: অফ কম্বিনেশন দ্বারা উপস্থাপিত হতে পারে।

std::lessঅদ্ভুত আইএসএ'র পয়েন্টারে সি ++ লাগতে পারে ব্যয়বহুল , যেমন একটি বিভাগটিকে "নরমালাইজ" করতে হবে : অফসেট পেতে x86-16 এ অফসেট <= 15. তবে, এটি প্রয়োগ করার মতো কোনও বহনযোগ্য উপায় নেই । একটি uintptr_t(বা একটি পয়েন্টার অবজেক্টের অবজেক্ট-উপস্থাপনা) স্বাভাবিক করার জন্য প্রয়োজনীয় ম্যানিপুলেশন বাস্তবায়ন-নির্দিষ্ট।

তবে এমনকি এমন সিস্টেমে যেখানে সি ++ std::lessব্যয়বহুল হতে হবে, <তা করার দরকার নেই। উদাহরণস্বরূপ, একটি "বৃহত" মেমরির মডেল ধরে নেওয়া যেখানে কোনও বস্তু এক বিভাগের মধ্যে ফিট করে, <কেবল অফসেট অংশের তুলনা করতে পারে এবং সেগমেন্ট অংশের সাথেও বিরক্ত করতে পারে না। (একই বস্তুর অভ্যন্তরের পয়েন্টারগুলির একই বিভাগ থাকবে, এবং অন্যথায় এটি সি সি ++ 17-তে ইউবি পরিণত হয়েছে যা কেবল "অনির্ধারিত" হিসাবে পরিবর্তিত হয়েছে, এটি এখনও সাধারণকরণ বাদ দিতে পারে এবং কেবল অফসেটের তুলনা করতে পারে)) এটি কোনও অংশে সমস্ত পয়েন্টারকে ধরেই নিচ্ছে কোনও বস্তুর সর্বদা একই segমান ব্যবহার করে , কখনই স্বাভাবিক হয় না। আপনি "বিশাল" মেমরির মডেলের বিপরীতে কোনও এবিআইয়ের "বৃহত্তর" প্রয়োজনের প্রত্যাশা এটিই। ( মন্তব্যে আলোচনা দেখুন )।

(যেমন একটি মেমরির মডেলটিতে উদাহরণস্বরূপ সর্বোচ্চ object৪kiB আকারের আকার থাকতে পারে তবে অনেকগুলি বৃহত্তর সর্বোচ্চ মোট ঠিকানা স্পেসে এমন অনেকগুলি সর্বোচ্চ আকারের অবজেক্টের জন্য জায়গা রয়েছে ISO আইএসও সি বাস্তবায়নগুলিকে অবজেক্ট আকারের সীমা থাকতে পারে যা তার চেয়ে কম থাকে) সর্বোচ্চ মান (স্বাক্ষরবিহীন) size_tপ্রতিনিধিত্ব করতে পারে, SIZE_MAXউদাহরণস্বরূপ এমনকি ফ্ল্যাট মেমরি মডেল সিস্টেমগুলিতেও, জিএনইউ সি সর্বোচ্চ বস্তুর আকার সীমাবদ্ধ করে PTRDIFF_MAXতাই আকার গণনা স্বাক্ষরিত ওভারফ্লোটিকে উপেক্ষা করতে পারে)) মন্তব্যগুলিতে এই উত্তর এবং আলোচনা দেখুন ।

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

x86 রিয়েল-মোড বিভাজন কেবলমাত্র অ-ফ্ল্যাট মেমরি মডেলই সম্ভব নয় , এটি সি / সি ++ বাস্তবায়ন দ্বারা কীভাবে পরিচালিত হয়েছে তা চিত্রিত করার জন্য এটি কেবল একটি কার্যকর কংক্রিটের উদাহরণ। বাস্তব জীবনে, বাস্তবায়নগুলি farবনাম nearপয়েন্টারগুলির ধারণার সাথে আইএসও সি প্রসারিত করে , প্রোগ্রামাররা কিছু সাধারণ ডেটা বিভাগের সাথে সম্পর্কিত, 16-বিট অফসেট অংশের কাছাকাছি কেবল স্টোরেজ / পাস দিয়ে চলে যেতে পারলে তা চয়ন করতে দেয়।

তবে একটি খাঁটি আইএসও সি বাস্তবায়নের জন্য একটি ছোট মেমোরি মডেল (১ 64-বিট পয়েন্টারযুক্ত একই B৪কিবি কোড বাদে সমস্ত কিছু) বা সমস্ত পয়েন্টারগুলি 32-বিট সহ বৃহত বা বিশালের মধ্যে নির্বাচন করতে হবে। কিছু লুপগুলি কেবল অফসেট অংশটি বাড়িয়ে অনুকূলিত করতে পারে তবে পয়েন্টার অবজেক্টগুলি আরও ছোট হওয়ার জন্য অনুকূলিত হতে পারে না।


যদি আপনি জানতেন যে প্রদত্ত যে কোনও প্রয়োগের জন্য যাদুর হেরফেরটি কী, আপনি খাঁটি সিতে এটি প্রয়োগ করতে পারেন । সমস্যাটি হ'ল বিভিন্ন সিস্টেমগুলি বিভিন্ন ঠিকানা ব্যবহার করে এবং বিশদ কোনও পোর্টেবল ম্যাক্রো দ্বারা প্যারামিটারাইজড হয় না।

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

(অবশ্যই x86 এর মূলধারার ওএসগুলি ফ্ল্যাট মেমরি মডেল ব্যবহার করে তাই সেগমেন্ট বেসটি সর্বদা 0 থাকে (থ্রেড-লোকাল স্টোরেজ ব্যবহার করে fsবা gsবিভাগগুলি বাদে )) এবং কেবল 32-বিট বা 64-বিট "অফসেট" অংশটি পয়েন্টার হিসাবে ব্যবহৃত হয় ।)

আপনি ম্যানুয়ালি বিভিন্ন নির্দিষ্ট প্ল্যাটফর্মগুলির জন্য কোড যুক্ত করতে পারেন, উদাহরণস্বরূপ ডিফল্টরূপে ফ্ল্যাট অনুমান করে, বা #ifdefx86 রিয়েল মোড সনাক্ত করার জন্য uintptr_tএবং 16-বিট অংশে বিভক্ত হয়ে seg -= off>>4; off &= 0xf;সেই অংশগুলি আবার 32-বিট সংখ্যায় একত্রিত করতে পারেন।


বিভাগটি সমান না হলে কেন এটি ইউবি হবে?
ওক গাছের ফল

@ অ্যাখর্ন: অন্যভাবে যেভাবে বলতে হবে তা বোঝাতে হবে; স্থির করেছি। একই অবজেক্টের পয়েন্টারগুলির একই বিভাগ থাকবে, অন্যথায় ইউবি।
পিটার

তবে কেন আপনি কোনও ক্ষেত্রে এটি ইউবি বলে মনে করেন? (যুক্তিবিজ্ঞান উল্টানো বা না, আসলে আমি হয় খেয়ালই করেন নি)
ওক গাছের ফল

p < qসিবিতে ইউবি কি তারা যদি বিভিন্ন বস্তুকে নির্দেশ করে, তাই না? আমি জানি p - q
পিটার কর্ডস

1
@ অ্যাকর্ন: যাইহোক, আমি এমন কোনও ব্যবস্থা দেখছি না যা ইউবি ছাড়াই কোনও প্রোগ্রামে এলিয়াস (বিভিন্ন সেগ: বন্ধ, একই লিনিয়ার ঠিকানা) উত্পন্ন করবে। সুতরাং এটি সংযোজনকারীটিকে এড়ানোর জন্য তার পথ থেকে বেরিয়ে যেতে হবে এমন নয়; প্রতিটি বস্তুর অ্যাক্সেসে সেই অবজেক্টের segমান এবং অফসেট ব্যবহার করা হয় যা> = সেগমেন্টের মধ্যে অফসেট যেখানে সেই বস্তুটি শুরু হয়। সি এটি বিভিন্ন জিনিসকে পয়েন্টারগুলির মধ্যে অনেক কিছু করতে ইউবি করে তোলে, যেমন স্টাফ tmp = a-bএবং এরপরে b[tmp]অ্যাক্সেস সহ a[0]। বিভাগযুক্ত পয়েন্টার আলিয়াসিং সম্পর্কে এই আলোচনা কেন সেই নকশা-পছন্দটি বোধগম্য করে তোলে তার একটি ভাল উদাহরণ।
পিটার

17

আমি একবার এর আশেপাশে একটি উপায় সন্ধান করার চেষ্টা করেছি এবং আমি এমন একটি সমাধান পেয়েছি যা ওভারল্যাপিং অবজেক্টগুলির জন্য কাজ করে এবং বেশিরভাগ ক্ষেত্রে সংকলকটি "স্বাভাবিক" জিনিসটি ধরে নেয় ass

আপনি প্রথমে একটি মধ্যবর্তী অনুলিপি ছাড়াই স্ট্যান্ডার্ড সিতে মেমমোভ কীভাবে প্রয়োগ করবেন সেই পরামর্শটি কার্যকর করতে পারেন ? এবং তারপরে যদি এটি কার্যকর হয় না uintptr(তবে একটি র‍্যাপার টাইপের জন্য uintptr_tবা উপলভ্য unsigned long longকিনা uintptr_tতার উপর নির্ভর করে ) এবং সর্বাধিক সম্ভাব্য সঠিক ফলাফল পান (যদিও এটি কোনওভাবেই গুরুত্বপূর্ণ নয়):

#include <stdint.h>
#ifndef UINTPTR_MAX
typedef unsigned long long uintptr;
#else
typedef uintptr_t uintptr;
#endif

int pcmp(const void *p1, const void *p2, size_t len)
{
    const unsigned char *s1 = p1;
    const unsigned char *s2 = p2;
    size_t l;

    /* Check for overlap */
    for( l = 0; l < len; l++ )
    {
        if( s1 + l == s2 || s1 + l == s2 + len - 1 )
        {
            /* The two objects overlap, so we're allowed to
               use comparison operators. */
            if(s1 > s2)
                return 1;
            else if (s1 < s2)
                return -1;
            else
                return 0;
        }
    }

    /* No overlap so the result probably won't really matter.
       Cast the result to `uintptr` and hope the compiler
       does the "usual" thing */
    if((uintptr)s1 > (uintptr)s2)
        return 1;
    else if ((uintptr)s1 < (uintptr)s2)
        return -1;
    else
        return 0;
}

5

সি কি অনুরূপ কার্যকারিতা সহ এমন কিছু প্রস্তাব দেয় যা স্বেচ্ছাসেবী পয়েন্টারগুলির সাথে নিরাপদে তুলনা করতে দেয়।

না


প্রথমে কেবলমাত্র অবজেক্ট পয়েন্টার বিবেচনা করা যাক । ফাংশন পয়েন্টারগুলি সম্পূর্ণ অন্যান্য উদ্বেগ নিয়ে আসে।

২ টি পয়েন্টারে p1, p2বিভিন্ন এনকোডিং থাকতে পারে এবং একই ঠিকানায় নির্দেশ করতে p1 == p2পারে যদিও memcmp(&p1, &p2, sizeof p1)0 না হলেও এই জাতীয় স্থাপত্যগুলি বিরল are

তবুও এই পয়েন্টারকে রূপান্তর করার uintptr_tজন্য একই সংখ্যার ফলাফলের প্রয়োজন হয় না (uintptr_t)p1 != (uinptr_t)p2

(uintptr_t)p1 < (uinptr_t)p2 নিজেই কার্যকর আইনী কোড, কার্যকারিতার জন্য আশাকে সরবরাহ নাও করতে পারে।


যদি কোডটিকে সত্যিকারের সম্পর্কযুক্ত পয়েন্টারগুলির তুলনা করতে হয় তবে একটি সহায়ক ফাংশন গঠন করুন less(const void *p1, const void *p2)এবং প্ল্যাটফর্মের জন্য নির্দিষ্ট কোডটি সম্পাদন করুন।

সম্ভবত:

// return -1,0,1 for <,==,> 
int ptrcmp(const void *c1, const void *c1) {
  // Equivalence test works on all platforms
  if (c1 == c2) {
    return 0;
  }
  // At this point, we know pointers are not equivalent.
  #ifdef UINTPTR_MAX
    uintptr_t u1 = (uintptr_t)c1;
    uintptr_t u2 = (uintptr_t)c2;
    // Below code "works" in that the computation is legal,
    //   but does it function as desired?
    // Likely, but strange systems lurk out in the wild. 
    // Check implementation before using
    #if tbd
      return (u1 > u2) - (u1 < u2);
    #else
      #error TBD code
    #endif
  #else
    #error TBD code
  #endif 
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.