2017-12-21 163 views
30

पहले, वास्तविक सवाल से पहले एक छोटे से अस्वीकरण:आकार (टी) और असुरक्षित .izeOf <T>() के बीच क्या अंतर है? सब से

मैं जानता हूँ कि बंद के एक बहुत देखते हैं/sizeof ऑपरेटर और Marshal.SizeOf<T> विधि के बीच अंतर के बारे में सवाल नकल, और मैं के बीच अंतर समझना है दो। यहाँ मैं नई Unsafe वर्ग

तो में SizeOf<T> विधि के बारे में बात कर रहा हूँ, मुझे यकीन है कि मैं इन दो आपरेशन के बीच वास्तविक अंतर को समझते हैं, और नहीं कर रहा हूँ वहाँ एक विशिष्ट अंतर है कि जब कोई struct पर विधि का उपयोग/विशेष रूप से वर्ग।

sizeof ऑपरेटर एक प्रकार नाम लेता है और कामयाब बाइट्स यह जब आवंटित लेने के लिए माना जाता है की संख्या देता है (यानी। एक Int32 4 वापस आ जाएगी, उदाहरण के लिए)।

दूसरी ओर Unsafe.SizeOf<T> विधि, Unsafe कक्षा में सभी अन्य तरीकों की तरह आईएल में कार्यान्वित किया जाता है, और कोड यहाँ पर देख रहे हैं कि वह क्या करता है:,

.method public hidebysig static int32 SizeOf<T>() cil managed aggressiveinlining 
{ 
    .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = (01 00 00 00) 
    .maxstack 1 
    sizeof !!T 
    ret 
} 

अब अगर मैं नहीं कर रहा हूँ गलत, कोड सिर्फ sizeof !!T पर कॉल कर रहा है जो sizeof(T) जैसा है (sizeof ऑपरेटर को टाइप नाम T के साथ कॉल करना), तो क्या उनमें से दो बिल्कुल बराबर नहीं होंगे?

इसके अलावा, मुझे लगता है कि यह विधि पहली पंक्ति में एक बेकार वस्तु (NonVersionableAttribute) आवंटित कर रही है, तो क्या इससे थोड़ी मात्रा में स्मृति को ढेर-आवंटित नहीं किया जाएगा?

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

यह कहना सुरक्षित है कि दो तरीकों पूरी तरह से बराबर हैं और इसलिए यह, क्लासिक sizeof ऑपरेटर का उपयोग करने के रूप में वह भी में उस विशेषता के आवंटन से बचने के सिर्फ बेहतर है है SizeOf<T> विधि? क्या यह SizeOf<T> विधि इस बिंदु पर सुविधा के लिए Unsafe कक्षा में जोड़ा गया था?

+1

'.custom' बयान सिर्फ आपको बताता है कि एक कस्टम-विशेषता इस विधि से संबंधित वर्तमान नहीं है। चूंकि कस्टम-विशेषताएं केवल मेटाडेटा हैं, वे नियमित विधि कॉल में शामिल नहीं हैं। – thehennyy

+0

बस एक स्पष्टीकरण, क्या यह एक बीसीएल वर्ग है जिसे मैं अनजान हूं, या कुछ [तृतीय पक्ष एक्सटेंशन] (https://github.com/DotNetCross/Memory.Unsafe)? आप सही हैं कि यह कुछ भी नहीं करता है, शायद विचार भविष्य में कुछ क्रॉस-प्लेटफार्म जादूगर के लिए "हुक" प्रदान करना था? – Groo

+2

@ ग्रूओ यह एक नई कक्षा है जिसे CoreFX में जोड़ा गया है। मुझे .NET कोर 2.0 के साथ विश्वास है (बिल्कुल यकीन नहीं है, लेकिन यह .NET कोर 2.0 में वैसे भी है)। यहां देखें: https://docs.microsoft.com/it-it/dotnet/api/system.runtime.compilerservices.unsafe?view=netcore-2.0 – Sergio0694

उत्तर

21

इस पद्धति वास्तव में सिर्फ sizeof आईएल अनुदेश का उपयोग करता है - वहाँ, नियमित रूप से sizeof ऑपरेटर के साथ एक अंतर है, क्योंकि इस ऑपरेटर मनमाना प्रकार के लिए लागू नहीं किया जा सकता:

एक के लिए बाइट में आकार प्राप्त करने के लिए प्रयोग किया जाता है अप्रबंधित प्रकार।

Enum प्रकार

सूचक प्रकार

उपयोगकर्ता-परिभाषित structs है कि किसी भी शामिल नहीं है: अप्रबंधित प्रकार में निर्मित प्रकार है कि तालिका इस प्रकार में सूचीबद्ध हैं, और यह भी निम्नलिखित शामिल हैं खेतों या गुण है कि संदर्भ प्रकार

हैं आप Unsafe.SizeOf के अनुरूप लिखने की कोशिश है - यह काम नहीं करेगा:

public static int SizeOf<T>() 
{ 
    // nope, will not compile 
    return sizeof(T); 
} 

तो Unsafe.SizeOf लिफ्टों sizeof ऑपरेटर के प्रतिबंध और आप उपयोग करना (संदर्भ प्रकार है जिसके लिए यह संदर्भ के आकार वापस आ जाएगी सहित) मनमाना प्रकार के साथ आईएल sizeof अनुदेश अनुमति देते हैं।

विशेषता का निर्माण आप आईएल में देखते हैं के लिए के रूप में - कि इसका मतलब यह नहीं विशेषता प्रत्येक कॉल के लिए instantiated किया जाएगा - कि विभिन्न सदस्यों के साथ गुण (इस मामले में विधि) जोड़ने के लिए बस आईएल वाक्य रचना है।

उदाहरण:

public struct Test { 
    public int Int1; 
} 

static void Main() { 
    // works 
    var s1 = Unsafe.SizeOf<Test>(); 
    // doesn't work, need to mark method with "unsafe" 
    var s2 = sizeof(Test);    
} 

एक और उदाहरण:

public struct Test { 
    public int Int1; 
    public string String1; 
} 


static unsafe void Main() { 
    // works, return 16 in 64bit process - 4 for int, 4 for padding, because 
    // alignment of the type is the size of its largest element, which is 8 
    // and 8 for string 
    var s1 = Unsafe.SizeOf<Test>(); 
    // doesn't work even with unsafe, 
    // cannot take size of variable of managed type "Test" 
    // because Test contains field of reference type (string) 
    var s2 = sizeof(Test);       
} 
+0

बिल्कुल सही, धन्यवाद! यह थोडा अजीब है कि हमें ऐसा करने में सक्षम होने के लिए इस विधि की आवश्यकता है, मुझे आश्चर्य है कि उन्होंने सी # कंपाइलर को अपडेट नहीं करना चुना ताकि 'आकार' ऑपरेटर को उस अतिरिक्त आईएल विधि के बिना ऐसा करने दें। इसके अलावा, एक सेकंड प्रतीक्षा करें, एक 'int' नहीं होना चाहिए (क्योंकि यह एक' Int32' संरचना है) हमेशा 4-बाइट लंबा हो, यहां तक ​​कि मैं 64-बिट प्रक्रियाओं को भी करता हूं? 'टेस्ट' का आकार 12 बाइट नहीं होना चाहिए? – Sergio0694

+1

@ Sergio0694 हाँ यकीन है, int 4 बाइट्स है और दूसरा 4 बाइट पैडिंग है, इसे ठीक किया गया है। क्यों नहीं आकार के ऑपरेटर को बदलना - मुझे बिल्कुल बिल्कुल पता नहीं है, लेकिन मुझे लगता है कि इसके लिए कंपाइलर में परिवर्तन की आवश्यकता है और 'असुरक्षित। सिस्टऑफ' को किसी भी बदलाव की आवश्यकता नहीं है। इसके अलावा, 'आकार' काम करने के लिए पहली जगह में एक कारण था, इसलिए मुझे लगता है कि आपको वास्तव में यह जानने की ज़रूरत है कि आप 'असुरक्षित। आकार' का उपयोग करते समय क्या कर रहे हैं (यह सब के बाद असुरक्षित है)। – Evk

+0

समझ में आता है, अतिरिक्त स्पष्टीकरण के लिए धन्यवाद! पूरी तरह से ऑफसेट संरेखण के बारे में भूल गए, यह थोड़ी देर के बाद से मैंने सी में कोड किया था और आप प्रबंधित भाषा का उपयोग करते समय इन छोटे विवरणों को भूल जाते हैं, अहाहाह – Sergio0694

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