12

मुझे वर्तमान में ऑपरेटरों के साथ नई समस्या का सामना करना पड़ रहा है। निम्नलिखित कोड का उपयोग करके, मैं आउटपुट बनाना चाहता हूं जो सी # में if ... else जोड़ी का उपयोग करते समय समान होगा।सी # प्रतिबिंब: यदि ... और?

var method = new DynamicMethod("dummy", null, Type.EmptyTypes); 
var g = method.GetILGenerator(); 

g.Emit(OpCodes.Ldstr, "string"); 
g.Emit(OpCodes.Ldstr, "string"); 
g.Emit(OpCodes.Call, typeof(String).GetMethod("op_Equality", new Type[]{typeof(string), typeof(string)})); 
g.Emit(OpCodes.Ldc_I4, 0); 
g.Emit(OpCodes.Ceq); 
g.Emit(OpCodes.Brtrue_S,); 

var action = (Action)method.CreateDelegate(typeof(Action)); 
action(); 

Console.Read(); 

मेरे प्रश्न हैं:

  1. मैं एक निर्देश का पता शाखा opcodes के लिए एक पैरामीटर के रूप में यह पारित करने के लिए कैसे मिल सकता है?
  2. वहाँ BR और BR_S, Brtrue और Brtrue_S, Brfalse और Brfalse_S और इसी तरह के निर्देश के बीच कोई अंतर है?

धन्यवाद।

+3

जैसा कि अन्य ने उल्लेख किया है, शाखा निर्देशों के "_S" संस्करण 4-बाइट ऑफ़सेट के बजाय 1-बाइट लेते हैं। यदि आप जानते हैं कि आपकी शाखा हमेशा उपलब्ध सीमा के भीतर होगी (-128 बाइट्स +127 बाइट्स), तो आप उन्हें उपयोग करके अधिक कॉम्पैक्ट कोड प्राप्त करेंगे, हालांकि यदि आप उन्हें ऑफ़सेट के साथ लेबल पर कूदने के लिए उपयोग करने का प्रयास करते हैं इस सीमा, प्रतिनिधि बनाने के दौरान एक अपवाद फेंक दिया जाएगा। – Iridium

उत्तर

8

ILGenerator.ILOffset आपको आईएल स्ट्रीम में वर्तमान ऑफ़सेट देता है, यदि आप यही चाहते हैं। गोरिक के सुझाव के अनुसार, आप DefineLabel और MarkLabel का भी उपयोग कर सकते हैं।

brtrue.s और brtrue के बीच एकमात्र अंतर यह है कि brtrue.sbrtrue का संक्षिप्त संस्करण है। brtrue एक 4-बाइट ऑफ़सेट का उपयोग करता है और brtrue.s 1-बाइट ऑफसेट का उपयोग करता है। यह brfalse और brfalse.s (और br/br.s) के लिए लागू होता है।

जो आईएल निर्देश के एकमात्र छोटे संस्करण नहीं हैं, वहां अन्य छोटे निर्देश भी हैं, जैसे ldc.i4.0 - ldc.i4.8 पूर्णांक लोड करने के लिए। वे मुख्य रूप से छोटी बाइनरी पैदा करने के लिए उपयोगी होते हैं, लेकिन मुझे नहीं लगता कि अन्यथा कोई बड़ा अंतर है।

8
  1. आप शाखा का लक्ष्य स्थान निर्धारित करने के DefineLabel और MarkLabel विधियों के संयोजन का उपयोग कर सकते हैं। ऐसा करने के लिए, आपको आवश्यक लेबलों की घोषणा करें - equal और notequal जैसे कुछ। फिर आप अपने आईएल में स्पॉट्स को चिह्नित कर सकते हैं जहां लेबल मौजूद होना चाहिए। एक बार ऐसा करने के बाद, आप इस लेबल में अपने शाखा निर्देश का लक्ष्य निर्धारित कर सकते हैं।

    // Define labels 
    Label equal = g.DefineLabel(); 
    Label notEqual = g.DefineLabel(); 
    Label endOfMethod = g.DefineLabel(); 
    // your logic here 
    g.Emit(OpCodes.Brtrue_S, equal); 
    g.MarkLabel(equal); 
    // some code if they are equal 
    g.MarkLabel(notEqual); 
    // some code if they are not equal 
    g.MarkLabel(endOfMethod); // this marks the return point 
    g.Emit(OpCodes.Ret); 
    
  2. के बीच Br, Brtrue, और Brfalse और उनके _S समकक्षों अंतर कूद की लंबाई है। _S संक्षिप्त रूप इंगित करता है; लक्ष्य निर्देश अगले निर्देश से 1-बाइट हस्ताक्षरित ऑफ़सेट है। मानक (गैर-लघु) रूप में, लक्ष्य है जो 4-बाइट ऑफसेट द्वारा दर्शाया गया है।

4

यह मेरे लिए नया है, लेकिन जाहिरा तौर पर एक छोटे से खोज से आप पहले से कुछ बिंदु पर

Label targetInstruction = g.DefineLabel(); 

फोन करके पता मिल (जैसे कि आपका पहला Emit से पहले?), और फिर

g.MarkLabel(targetInstruction); 

बस से पहले लाइन आप को शाखा करना चाहते उत्सर्जन। फिर यह Label आपके Br____ ऑपोड का तर्क है।

Br, Brtrue और Brfalse के बीच का अंतर यह है कि ब्र हमेशा शाखाएं होती है, और अन्य दो स्टैक से मूल्य मानते हैं और केवल शाखा ही सही या गलत होती है। (तो हाँ, एक बड़ा अंतर है!) _S "लघु रूप" का प्रतीक है लेकिन मुझे यकीन नहीं है कि इसका क्या अर्थ है।

संबंधित मुद्दे