2012-09-24 7 views
10

मैं कई structs अनुक्रमिक लेआउट है कि है:Marshal.SizeOf अतिरिक्त बाइट्स देता

struct S1 
{ 
    Guid id; 
} 

struct S2 
{ 
    Guid id; 
    short s; 
} 

struct S3 
{ 
    Guid id; 
    short s; 
    short t; 
} 

ऊपर struct प्रकार पर Marshal.SizeOf कॉलिंग, मुझे मिल गया:

Size: 
S1 = 16, as expected. 
S2 = 20, copied an instance to a byte array, it only occupies first 18 bytes. 
S3 = 20. 

मेरा प्रश्न यही कारण है कि एस 2 का आकार 20 है लेकिन 18 नहीं। और यह समस्या तब होती है जब Guid संरचना में है।

क्षमा करें msdn से कोई उपयोगी जानकारी नहीं मिल सकती है। मुझे पता है कि Marshal.SizeOf मेमोरी में टाइप किए जाने वाले स्थान का आकार देता है, लेकिन मुझे यह जानना है कि आकार को 4 से अधिक बनाने के लिए 2 अतिरिक्त बाइट्स क्यों हैं।

और मैं इस "समस्या" से कैसे बच सकता हूं?

बहुत बहुत धन्यवाद!

+0

संरचना मेमोरी लेआउट पर @ हंस पासेंट के बहुत गहन [उत्तर] (http://stackoverflow.com/a/3362736/1289454) पर एक नज़र डालें। उनका दावा है कि 'Marhsal.SizeOf' केवल एक guesstimate प्रदान कर सकते हैं। – gowansg

उत्तर

9

यह एक संरचना से जुड़े अंतर्निहित [स्ट्रक्चरलाइट] की वजह से है, पैक फ़ील्ड महत्वपूर्ण है। यह निर्देश देता है कि मार्शल के बाद संरचना के सदस्यों को कैसे गठबंधन किया जाता है। पैक के लिए डिफ़ॉल्ट मान 8 है। जो कहता है कि किसी भी सदस्य आकार में 8 बाइट्स के बराबर या बराबर है, गठबंधन किया गया है। दूसरे शब्दों में, एक छोटा सा ऑफसेट से गठबंधन किया जाएगा जो कि 2 से अधिक है, एक int से 4, लंबा या डबल 8।

मुख्य बिंदु यह है कि संरचनाओं की एक सरणी बनने पर संरेखण अभी भी काम करना चाहिए । आसान एक सरल उदाहरण के साथ प्रदर्शन किया:

using System; 
using System.Runtime.InteropServices; 

class Program { 
    static void Main(string[] args) { 
     Console.WriteLine(Marshal.SizeOf(typeof(Example))); 
     Console.ReadLine(); 
    } 
} 
struct Example { 
    public int a; 
    public short b; 
} 

आउटपुट: 8

a सदस्य आकार में वृद्धि करने के लिए, दो अतिरिक्त पैडिंग बाइट्स संरचना करने के लिए जोड़ रहे हैं सुनिश्चित करने के लिए कि पूर्णांक अभी भी करने के लिए एक ऑफसेट संरेखित करता बलों यह एक सरणी में प्रयुक्त होता है जब 4 का एक बहु है। आप विशेषता लगाने से परिणाम बदल सकते हैं:

[StructLayout(LayoutKind.Sequential, Pack = 2)] 
struct Example { 
    public int a; 
    public short b; 
} 

आउटपुट: 6

a सदस्य अब हो जाएगा गलत गठबंधन जब struct एक सरणी में प्रयोग किया जाता है।

वापस ग्रिड पर, आप इसे घोषणा से नहीं देख सकते हैं लेकिन यह आंतरिक रूप से कई सदस्यों से बना है। पहला वाला निजी क्षेत्र _a है और यह एक int है।इसलिए ग्रिड को 4 बाइट संरेखण की आवश्यकता है। तो सरणी में उपयोग होने पर आपकी संरचना को ठीक से संरेखित करने के लिए 2 अतिरिक्त पैडिंग बाइट की आवश्यकता होती है। 18 बाइट प्राप्त करने के लिए आपको पैक 2 या पैक 2 को एस 2 पर चाहिए।

structs पर अधिक पृष्ठभूमि और this answer में .NET में विशेष तरीके से उनका इलाज किया जाता है।

+0

बहुत बहुत धन्यवाद। – user1695516

0

मैं आपको अपनी संरचना परिभाषाओं पर StructLayoutAttribute का उपयोग नहीं कर रहा हूं। इसलिए आप नहीं जान पाएंगे कि वे "निर्धारित" कैसे हैं। आप कैसे बता सकते हैं कि उनके पास अनुक्रमिक लेआउट है?

कुछ सूत्रों: sizeof() structures not known. Why? और When should I explicitly specify a StructLayout?

0

मेरा मानना ​​है कि ऐसा इसलिए है क्योंकि कुछ आइटम 4 बाइट (या 8 बाइट) सीमाओं को स्मृति में गठबंधन किया जाना चाहिए। इसलिए संरचना को इस आकार का एक बहुतायत बनाया जाता है ताकि structs के सरणी सभी सही ढंग से गठबंधन किए जाएंगे। एक स्ट्रिंग समेत एक 64-बिट मशीन पर यह 8 बाइट्स के एकाधिक होने के लिए मजबूर करता है; GUID को केवल 64-बिट्स पर भी 4 बाइट्स की आवश्यकता होती है। यदि GUID युक्त संरचना आकार में 4 बाइट्स का एक से अधिक नहीं था तो कुछ GUIDs इन structs की सरणी में 4-बाइट सीमा पर नहीं होंगे। मुझे नहीं लगता कि आप 'समस्या' से बच सकते हैं - यह एक समस्या क्यों है?

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