সি # সংকলক কেন এটি অনুবাদ করে! = তুলনা যেমন এটি>> তুলনা?


147

আমি খাঁটি সুযোগে আবিষ্কার করেছি যে সি # সংকলক এই পদ্ধতিটি ঘুরিয়েছে:

static bool IsNotNull(object obj)
{
    return obj != null;
}

... এই সিআইএল মধ্যে :

.method private hidebysig static bool IsNotNull(object obj) cil managed
{
    ldarg.0   // obj
    ldnull
    cgt.un
    ret
}

… বা, আপনি যদি দ্রবীভূত সি # কোডটি দেখতে পছন্দ করেন:

static bool IsNotNull(object obj)
{
    return obj > null;   // (note: this is not a valid C# expression)
}

কীভাবে আসবে যে !=" >" হিসাবে অনুবাদ হয় ?

উত্তর:


201

সংক্ষিপ্ত উত্তর:

আইএলে কোনও "তুলনা-সমান" নির্দেশনা নেই, সুতরাং সি # !=অপারেটরের কোনও সঠিক চিঠিপত্র নেই এবং আক্ষরিক অনুবাদ করা যায় না।

তবে "তুলনা-সমান" নির্দেশনা রয়েছে ( ceq, ==অপারেটরের সাথে সরাসরি চিঠিপত্র ), তাই সাধারণ ক্ষেত্রে এটি x != yতার সামান্য দীর্ঘ সমতুল্যর মতো অনুবাদ হয় (x == y) == false

নেই এছাড়াও একটি "তুলনা-বেশী বেশী" আইএল (নির্দেশ cgt) যা কম্পাইলার নির্দিষ্ট শর্টকাট (অর্থাত উৎপন্ন খাটো আইএল কোড), এক হচ্ছে নাল বিরুদ্ধে বস্তুর যে বৈষম্য তুলনা নিতে অনুমতি দেয়, obj != null, অনুবাদ পেতে, যেন তারা কোন " obj > null"।

আসুন আরও কিছু বিশদে।

আইএল-তে যদি "তুলনা-সম-সমান" নির্দেশনা না থাকে, তবে নিম্নলিখিত পদ্ধতিটি সংকলক দ্বারা কীভাবে অনুবাদ করা হবে?

static bool IsNotEqual(int x, int y)
{
    return x != y;
}

ইতিমধ্যেই যেমন উপরে বললেন, কম্পাইলার চালু হবে x != yমধ্যে (x == y) == false:

.method private hidebysig static bool IsNotEqual(int32 x, int32 y) cil managed 
{
    ldarg.0   // x
    ldarg.1   // y
    ceq
    ldc.i4.0  // false
    ceq       // (note: two comparisons in total)
    ret
}

দেখা যাচ্ছে যে সংকলকটি সর্বদা এই মোটামুটি দীর্ঘ-বায়ুযুক্ত প্যাটার্নটি উত্পাদন করে না। আসুন দেখা যাক আমরা যখন yধ্রুবক 0 দ্বারা প্রতিস্থাপন করি তখন কী হয় :

static bool IsNotZero(int x)
{
    return x != 0;
}

উত্পাদিত আইএল সাধারণ ক্ষেত্রেগুলির তুলনায় কিছুটা কম:

.method private hidebysig static bool IsNotZero(int32 x) cil managed 
{
    ldarg.0    // x
    ldc.i4.0   // 0
    cgt.un     // (note: just one comparison)
    ret
}

সংকলক স্বাক্ষরিত পূর্ণসংখ্যার দুটি পরিপূরক (যেখানে, যদি বিট নিদর্শনগুলি স্বাক্ষরবিহীন পূর্ণসংখ্যার হিসাবে ব্যাখ্যা করা হয় - তবে এর .unঅর্থ - 0 এর সবচেয়ে কম সম্ভাব্য মান আছে) এর সুবিধা গ্রহণ করতে পারে, তাই এটি অনুবাদ করে x == 0যেমন এটি ছিল unchecked((uint)x) > 0

দেখা যাচ্ছে যে সংকলক বৈষম্য পরীক্ষার জন্য একই কাজ করতে পারে null:

static bool IsNotNull(object obj)
{
    return obj != null;
}

সংকলক প্রায় একই আইএল উত্পাদন করে IsNotZero:

.method private hidebysig static bool IsNotNull(object obj) cil managed 
{
    ldarg.0
    ldnull   // (note: this is the only difference)
    cgt.un
    ret
}

স্পষ্টতই, সংকলকটিকে ধরে নিতে অনুমতি দেওয়া হয় যে nullরেফারেন্সের বিট প্যাটার্নটি কোনও বস্তুর রেফারেন্সের জন্য সম্ভব সবচেয়ে ছোট বিট প্যাটার্ন।

এই শর্টকাটটি স্পষ্টভাবে কমন ল্যাঙ্গুয়েজ ইনফ্রাস্ট্রাকচার অ্যানোটেটেড স্ট্যান্ডার্ডে (অক্টোবর 2003 থেকে প্রথম সংস্করণ) উল্লেখ করা হয়েছে (পৃষ্ঠায় 491 পৃষ্ঠায়, টেবিল 6-4 এর পাদটীকা হিসাবে, "বাইনারি তুলনা বা শাখা অপারেশনস"):

" cgt.unঅবজেক্টআর্ফস (ও) এ " অনুমোদিত এবং যাচাইযোগ্য। এটি কোনও অবজেক্টরিফকে শূন্যের সাথে তুলনা করার সময় ব্যবহৃত হয় (কোনও "তুলনা-সমান" নির্দেশনা নেই, যা অন্যথায় আরও সুস্পষ্ট সমাধান হতে পারে)।


3
দুর্দান্ত উত্তর, মাত্র একটি নিট: দু'জনের পরিপূরক এখানে প্রাসঙ্গিক নয়। এটি কেবলমাত্র স্বাক্ষরিত পূর্ণসংখ্যাগুলি এমনভাবে সংরক্ষণ করা হয় যে intসীমার মধ্যে অ-নেতিবাচক মানগুলিতে intযেমন হয় তেমন প্রতিনিধিত্ব থাকে uint। এটি দু'জনের পরিপূরকের চেয়ে অনেক বেশি দুর্বল প্রয়োজন।

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

3
@ এইচভিডি: ব্যাখ্যা করার জন্য ধন্যবাদ। আপনি ঠিক বলেছেন, এটি দু'জনের পরিপূরক নয় যে বিষয়টি গুরুত্বপূর্ণ; এটা প্রয়োজন যে আপনাকে উল্লেখ করেছে এবং সত্য যে cgt.unএকইরূপে একটি intএকটি হিসাবে uintঅন্তর্নিহিত বিট প্যাটার্ন পরিবর্তন না করে। (কল্পনা করুন যে, cgt.unপ্রথম যে ক্ষেত্রে আপনি সম্ভবত প্রতিস্থাপন করতে পারে সালে 0. সব ঋণাত্মক সংখ্যা ম্যাপিং দ্বারা ফিক্স underflows করার চেষ্টা করবে > 0জন্য != 0।)
stakx - আর অবদান

2
আমি অবাক করে দিয়েছি যে ব্যবহার করে অন্য একটির সাথে কোনও অবজেক্টের রেফারেন্সের তুলনা >করা যাচাইযোগ্য আইএল। এইভাবে কেউ দুটি নন-নাল অবজেক্টের তুলনা করতে পারে এবং বুলিয়ান রেজাল্ট পেতে পারে (যা নন-ডিস্ট্রিমেন্টিক)। এটি কোনও স্মৃতি-সুরক্ষা সমস্যা নয় তবে এটি অশুভ নকশার মতো মনে হয় যা নিরাপদ পরিচালিত কোডের সাধারণ চেতনাতে নয়। এই নকশাটি অবজেক্টের রেফারেন্সগুলি পয়েন্টার হিসাবে প্রয়োগ করা হয় তা ফাঁস করে দেয়। NET CLI এর নকশার ত্রুটির মত মনে হচ্ছে।
usr

3
@ আরআর: একেবারে! সিএলআই স্ট্যান্ডার্ডের III.1.1.4 বিভাগে বলা হয়েছে যে "অবজেক্ট রেফারেন্স (টাইপ ও) সম্পূর্ণ অস্বচ্ছ" এবং এটি "কেবলমাত্র তুলনামূলক ক্রিয়াকলাপগুলিই সমতা এবং বৈষম্য ..." সম্ভবত কারণ বস্তুর রেফারেন্স হয় না মেমরি অ্যাড্রেস পরিপ্রেক্ষিতে সংজ্ঞায়িত মান এছাড়াও ধারণার দিক থেকে (যেমন দেখুন সংজ্ঞা 0 থেকে পৃথক্ নাল রেফারেন্স রাখার যত্ন নেয় ldnull, initobjএবং newobj)। সুতরাং cgt.unনাল রেফারেন্সের বিরুদ্ধে অবজেক্ট রেফারেন্সের তুলনা করার ব্যবহারটি একাধিক উপায়ে III.1.1.4 বিভাগের বিপরীতে দেখা যায়।
স্টাকেক্স -
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.