बूलियन इन C # का आकार क्या है? क्या यह वास्तव में 4-बाइट्स लेता है?


137

मेरे पास बाइट्स और बुलियन के सरणियों के साथ दो संरचनाएं हैं:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct struct1
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public byte[] values;
}

[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct struct2
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public bool[] values;
}

और निम्नलिखित कोड:

class main
{
    public static void Main()
    {
        Console.WriteLine("sizeof array of bytes: "+Marshal.SizeOf(typeof(struct1)));
        Console.WriteLine("sizeof array of bools: " + Marshal.SizeOf(typeof(struct2)));
        Console.ReadKey();
    }
}

यह मुझे निम्न आउटपुट देता है:

sizeof array of bytes: 3
sizeof array of bools: 12

ऐसा लगता है कि booleanभंडारण के 4 बाइट्स लेता है। आदर्श रूप से boolean केवल एक बिट ( falseया true, 0या 1..) लेगा ।

यहाँ क्या हो रहा है? क्या booleanप्रकार वास्तव में इतना अक्षम है?


7
होल्ड-कारणों की चल रही लड़ाई में यह सबसे अधिक विडंबनापूर्ण संघर्ष है: जॉन और हंस के दो बेहतरीन जवाबों ने इसे बनाया, भले ही इस सवाल का जवाब तथ्यों, संदर्भों के बजाय लगभग पूरी तरह से राय पर आधारित होगा। या विशिष्ट विशेषज्ञता।
ताव

12
@TaW: मेरा अनुमान है कि करीबी वोट उत्तरों के कारण नहीं थे, लेकिन ओपी के मूल स्वर के बारे में जब उन्होंने पहली बार सवाल उठाया - उन्होंने स्पष्ट रूप से एक लड़ाई शुरू करने का इरादा किया था और एकमुश्त टिप्पणी में यह दिखा दिया था। अधिकांश क्रॉफ़्ट गलीचा के नीचे बह गया है, लेकिन मेरे मतलब की एक झलक पाने के लिए संशोधन इतिहास देखें।
BoltClock

1
BitArray का उपयोग क्यों नहीं किया जाता है?
'

जवाबों:


242

Bool प्रकार भाषा runtimes के बीच कई असंगत विकल्पों के साथ एक चेकर इतिहास रहा है। यह डेनिस रिची द्वारा बनाए गए ऐतिहासिक डिजाइन-विकल्प के साथ शुरू हुआ, जिस आदमी ने सी भाषा का आविष्कार किया था। यह एक नहीं था bool प्रकार, विकल्प था पूर्णांक जहां 0 से मूल्य का प्रतिनिधित्व करता झूठी और किसी भी अन्य मूल्य माना जाता था सच

इस पसंद को Winapi में आगे बढ़ाया गया था, जो पिनवोक का उपयोग करने का प्राथमिक कारण है, इसमें एक टाइफाइड है BOOLजिसके लिए सी कंपाइलर के इंट कीवर्ड के लिए एक उपनाम है । यदि आप एक स्पष्ट [मार्शल] विशेषता को लागू नहीं करते हैं, तो एक C # बूल एक BOOL में परिवर्तित हो जाता है, इस प्रकार एक क्षेत्र का निर्माण होता है जो 4 बाइट लंबा होता है।

आप जो भी करते हैं, आपकी संरचना की घोषणा के लिए आपके द्वारा इंटरॉप की गई भाषा में रनटाइम पसंद के साथ एक मैच होना चाहिए। जैसा कि नोट किया गया है, winapi के लिए BOOL लेकिन अधिकांश C ++ कार्यान्वयन ने बाइट को चुना , अधिकांश COM स्वचालन इंटरॉप VARIANT_BOOL का उपयोग करता है जो कि एक छोटा है

वास्तविक एक सी # का आकार boolएक बाइट है। सीएलआर का एक मजबूत डिजाइन-लक्ष्य यह है कि आप इसका पता नहीं लगा सकते हैं। लेआउट एक कार्यान्वयन विवरण है जो प्रोसेसर पर बहुत अधिक निर्भर करता है। वैरिएबल प्रकार और संरेखण के बारे में प्रोसेसर बहुत अशिष्ट हैं, गलत विकल्प प्रदर्शन को काफी प्रभावित कर सकते हैं और रनटाइम त्रुटियों का कारण बन सकते हैं। लेआउट को अनदेखा करके, .NET एक सार्वभौमिक प्रकार प्रणाली प्रदान कर सकता है जो वास्तविक रनटाइम कार्यान्वयन पर निर्भर नहीं करता है।

दूसरे शब्दों में, आपको हमेशा लेआउट को बंद करने के लिए रनटाइम पर एक संरचना को मार्शल करना होगा। जिस समय आंतरिक लेआउट से इंटरोप लेआउट में रूपांतरण किया जाता है। यह बहुत तेज़ हो सकता है यदि लेआउट समान है, धीमा है जब खेतों को फिर से व्यवस्थित करने की आवश्यकता होती है क्योंकि हमेशा संरचना की एक प्रति बनाने की आवश्यकता होती है। इसके लिए तकनीकी शब्द ब्लिटेबल है , देशी कोड के लिए एक सम्मोहक संरचना पास करना तेज़ है क्योंकि पिनवोक मार्शेलर केवल एक पॉइंटर पास कर सकता है।

प्रदर्शन भी मूल कारण है कि एक बूल एक बिट नहीं है। कुछ प्रोसेसर हैं जो सीधे सीधे पता करने योग्य बनाते हैं, सबसे छोटी इकाई एक बाइट है। एक अतिरिक्त निर्देश को बाइट से मछली को निकालने की आवश्यकता होती है, जो मुफ्त में नहीं आती है। और यह कभी भी परमाणु नहीं है।

C # संकलक अन्यथा आपको यह बताने में संकोच नहीं करता है कि यह 1 बाइट लेता है, उपयोग करें sizeof(bool)। यह अभी भी एक शानदार भविष्यवक्ता नहीं है कि कितने बाइट्स किसी क्षेत्र को रनटाइम पर लेते हैं, सीएलआर को .NET मेमोरी मॉडल को लागू करने की भी आवश्यकता होती है और यह वादा करता है कि सरल चर अपडेट परमाणु हैं । इसके लिए चर को ठीक से मेमोरी में संरेखित करने की आवश्यकता होती है ताकि प्रोसेसर इसे एकल मेमोरी-बस चक्र के साथ अपडेट कर सके। बहुत बार, एक बूल को वास्तव में इसकी वजह से स्मृति में 4 या 8 बाइट्स की आवश्यकता होती है। अतिरिक्त गद्दी जो यह सुनिश्चित करने के लिए जोड़ी गई थी कि अगला सदस्य ठीक से संरेखित हो।

सीएलआर वास्तव में लेआउट के अनदेखे होने का फायदा उठाता है, यह एक वर्ग के लेआउट का अनुकूलन कर सकता है और खेतों को फिर से व्यवस्थित कर सकता है ताकि पैडिंग कम से कम हो। तो, कहते हैं, यदि आपके पास बूल + इंट + बूल सदस्य के साथ एक वर्ग है, तो यह 1 + (3) + 4 + 1 + (3) मेमोरी का बाइट्स लेगा, (3) पैडिंग है, कुल 12 के लिए बाइट्स। 50% बर्बादी। स्वचालित लेआउट 1 + 1 + (2) + 4 = 8 बाइट्स के लिए पुन: व्यवस्थित करता है। केवल एक वर्ग में स्वचालित लेआउट होता है, संरचना में डिफ़ॉल्ट रूप से अनुक्रमिक लेआउट होता है।

अधिक स्पष्ट रूप से, एक बूल को C ++ प्रोग्राम में 32 बाइट्स की आवश्यकता हो सकती है जो एक आधुनिक C ++ कंपाइलर के साथ संकलित होती है जो AVX निर्देश सेट का समर्थन करता है। जो एक 32-बाइट संरेखण की आवश्यकता को लगाता है, बूल चर पैडिंग के 31 बाइट्स के साथ समाप्त हो सकता है। इसके अलावा कोर कारण। .NET घबराना SIMD निर्देशों का उत्सर्जन नहीं करता है, जब तक कि स्पष्ट रूप से लपेटा नहीं जाता है, यह संरेखण गारंटी नहीं प्राप्त कर सकता है।



2
एक रुचि रखने वाले लेकिन बेख़बर पाठक के लिए, क्या आप स्पष्ट करेंगे कि अंतिम पैराग्राफ़ को वास्तव में 32 बाइट्स पढ़ना चाहिए और बिट्स नहीं ?
सिल्ली फ्रीक

3
मुझे यकीन नहीं है कि मैं यह सब क्यों पढ़ रहा हूं (जैसा कि मुझे इस बारे में अधिक जानकारी की आवश्यकता नहीं है) लेकिन यह आकर्षक और अच्छी तरह से लिखा गया है।
फ्रैंक वी

2
@Silly - यह बाइट्स है । AVX एक निर्देश के साथ 8 फ्लोटिंग पॉइंट वैल्यू पर गणित करने के लिए 512 बिट चर का उपयोग करता है। ऐसे 512 बिट वैरिएबल के लिए 32 के अलाइनमेंट की जरूरत होती है।
हंस पैसेंट

3
वाह! एक पोस्ट ने समझने के लिए बहुत सारे विषयों को नरक बना दिया। इसलिए मुझे सिर्फ शीर्ष प्रश्न पढ़ना पसंद है।
चैतन्य गडकरी '

151

सबसे पहले, यह केवल इंटरोप के लिए आकार है। यह सरणी के प्रबंधित कोड में आकार का प्रतिनिधित्व नहीं करता है। वह 1 बाइट प्रति bool- कम से कम मेरी मशीन पर है। आप इस कोड के साथ अपने लिए इसका परीक्षण कर सकते हैं:

using System;
class Program 
{ 
    static void Main(string[] args) 
    { 
        int size = 10000000;
        object array = null;
        long before = GC.GetTotalMemory(true); 
        array = new bool[size];
        long after = GC.GetTotalMemory(true); 

        double diff = after - before; 

        Console.WriteLine("Per value: " + diff / size);

        // Stop the GC from messing up our measurements 
        GC.KeepAlive(array); 
    } 
}

अब, मान के अनुसार सरणियों के लिए, जैसा कि आप हैं, प्रलेखन कहता है:

जब ByValArrayMarshalAsAttribute.Value गुण सेट हो जाता है , तो SizeConst फ़ील्ड को सरणी में तत्वों की संख्या को इंगित करने के लिए सेट किया जाना चाहिए। ArraySubTypeक्षेत्र वैकल्पिक रूप से शामिल कर सकते हैं UnmanagedTypeसरणी तत्वों की जब यह स्ट्रिंग प्रकार के बीच अंतर करने के लिए आवश्यक है। आप इसका उपयोग UnmanagedTypeकेवल उस सरणी पर कर सकते हैं , जिसके तत्व किसी संरचना में फ़ील्ड के रूप में दिखाई देते हैं।

तो हम देखते हैं ArraySubType, और जिसका प्रलेखन है:

UnmanagedTypeसरणी के तत्वों के प्रकार को निर्दिष्ट करने के लिए आप इस पैरामीटर को गणना से मान पर सेट कर सकते हैं। यदि कोई प्रकार निर्दिष्ट नहीं है, तो प्रबंधित सरणी के तत्व प्रकार के अनुरूप डिफ़ॉल्ट अप्रबंधित प्रकार का उपयोग किया जाता है।

अब देख रहे हैं UnmanagedType, वहाँ:

बूल
ए 4-बाइट बूलियन मूल्य (सच! = 0, गलत = 0)। यह Win32 BOOL प्रकार है।

तो यह डिफ़ॉल्ट के लिए है bool, और यह 4 बाइट्स है क्योंकि यह Win32 BOOL प्रकार से मेल खाती है - इसलिए यदि आप किसी BOOLसरणी की अपेक्षा कोड के साथ इंटरऑपरेट कर रहे हैं , तो यह वही करता है जो आप चाहते हैं।

अब आप इसके बजाय इसे निर्दिष्ट कर सकते हैं , जिसे इस ArraySubTypeरूप I1में प्रलेखित किया गया है:

1-बाइट हस्ताक्षरित पूर्णांक। आप इस सदस्य का उपयोग बूलियन मान को 1-बाइट, C- शैली बूल (सही = 1, असत्य = 1) में बदलने के लिए कर सकते हैं।

इसलिए यदि आप जिस कोड के साथ इंटरप्रेट कर रहे हैं, वह प्रति मूल्य 1 बाइट की अपेक्षा रखता है, तो बस उपयोग करें:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.I1)]
public bool[] values;

आपका कोड तब यह दिखाएगा कि अपेक्षा के अनुसार 1 बाइट प्रति मूल्य लिया जा रहा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.