2010-01-22 13 views
7

मान लीजिए कि मेरे पास सी # संरचना है:संरचना ऑफसेट पाने के लिए सी # कमांड?

[StructLayout(LayoutKind.Explicit)] 
struct IMAGE_DOS_HEADER { 
    [FieldOffset(60)] public int e_lfanew; 
} 

अब मान लीजिए कि मैं किसी फ़ाइल से डेटा में पढ़ता हूं, जैसे:

byte[] data = new byte[4096]; 
FileStream f = new FileInfo(filename).Open(FileMode.Open, FileAccess.Read); 
int n = f.Read(data, 0, 4096); 

अब मैं यह सुनिश्चित करने के लिए n का परीक्षण करना चाहता हूं कि मैंने पढ़ा है e_lfanew के मान प्राप्त करने के लिए पर्याप्त बाइट्स। क्या कोई तरीका है कि मैं मूल्य 60 (फील्ड ऑफसेट) को पुनः टाइप किए बिना प्राप्त कर सकता हूं? मैं इस तरह कुछ ढूंढ रहा हूं:

if (n >= offsetof(IMAGE_DOS_HEADER.e_lfanew) + sizeof(int)) { 
    ... 
} 

क्या ऐसा कोई आदेश है? मेरे वास्तविक कोड में, मुझे इनमें से कई परीक्षण करना पड़ता है, और यह स्ट्रिंग में पूर्व फ़ील्ड जोड़कर या फ़ील्ड ऑफसेट विशेषताओं से मूल्यों की प्रतिलिपि बनाकर संख्याओं को टाइप करने के लिए कठिन और त्रुटि-प्रवण प्रतीत होता है। क्या कोई बेहतर तरीका है?

+0

, मुझे लगता है कि नहीं था मैं किसी भी असली जवाब (nobugz के छोड़कर) मिल चाहते हैं, और यहाँ मैं तीन विकल्प! मुझे शायद ही पता चले कि किसको चुनना है, इसलिए मैंने उन सभी को वोट दिया। बस स्थिरांक को परिभाषित करना एक उचित दृष्टिकोण है, लेकिन यह कष्टप्रद है कि यह संरचना के लेआउट को कैसे रोकता है। मैं अभी भी प्रबंधित/अप्रबंधित की सूक्ष्मता सीख रहा हूं, लेकिन मुझे लगता है कि wj32 सही है क्योंकि संकलक पहले से ही मुझे संरचना में पॉइंटर प्राप्त करने दे रहा है, मुझे पता है कि प्रबंधित/अप्रबंधित ऑफसेट समान हैं। तो मैं उनके जवाब के साथ जा रहा हूं क्योंकि ऐसा लगता है कि यह सबसे आसान-पढ़ने वाला कोड उत्पन्न करता है। इस तरह के महान उत्तरों के लिए सभी को धन्यवाद! –

उत्तर

17

उपयोग Marshal.OffsetOf: वाह

Marshal.OffsetOf(typeof(IMAGE_DOS_HEADER), "e_lfanew") 
+0

+1। वाह, यह वही है जो उसने पूछा (हालांकि मैं अभी भी nobugz के जवाब के साथ और अधिक आरामदायक महसूस करता हूं, मानते हैं कि यह व्यावहारिक है)। – Brian

+1

मुझे इस बारे में पता नहीं है; 'मार्शल' प्रबंधित और अप्रबंधित के बीच जा रहा है।इस प्रकार प्रलेखन से "ऑफसेटऑफ' अप्रबंधित संरचना लेआउट के संदर्भ में ऑफसेट प्रदान करता है, ** जो आवश्यक संरचना लेआउट ** के ऑफसेट से मेल नहीं खाता है।" तो कुछ मामलों में यह गलत जवाब दे सकता है। – jason

+5

और आप प्रबंधित संरचना ऑफ़सेट क्यों जानना चाहेंगे? यहां तक ​​कि यदि आप जानते थे कि आप इसे किसी भी तरह से उपयोग नहीं कर पाएंगे, क्योंकि संरचना के लिए सूचक भी प्राप्त करना मतलब है कि यह विचित्र है। आपका अवलोकन किसी भी व्यावहारिक उद्देश्यों के लिए पूरी तरह से अप्रासंगिक है। – wj32

6

हाँ आप प्रतिबिंब का उपयोग करके ऐसा कर सकते हैं।

FieldOffsetAttribute fieldOffset = 
    (FieldOffsetAttribute)typeof(IMAGE_DOS_HEADER) 
     .GetField("e_lfanew") 
     .GetCustomAttributes(
      typeof(FieldOffsetAttribute), 
      true 
     )[0]; 
Console.WriteLine(fieldOffset.Value); 

तुम भी एक अच्छा विधि में इस बारी कर सकते हैं:

static int FieldOffset<T>(string fieldName) { 
    if (typeof(T).IsValueType == false) { 
     throw new ArgumentOutOfRangeException("T"); 
    } 
    FieldInfo field = typeof(T).GetField(fieldName); 
    if (field == null) { 
     throw new ArgumentOutOfRangeException("fieldName"); 
    } 
    object[] attributes = field.GetCustomAttributes(
     typeof(FieldOffsetAttribute), 
     true 
    ); 
    if (attributes.Length == 0) { 
     throw new ArgumentException(); 
    } 
    FieldOffsetAttribute fieldOffset = (FieldOffsetAttribute)attributes[0]; 
    return fieldOffset.Value; 
} 

उपयोग:

Console.WriteLine(FieldOffset<IMAGE_DOS_HEADER>("e_lfanew")); 
+0

+1 सहमत हुए। प्रतिबिंब इस मुद्दे तक पहुंचने का सबसे सुरक्षित (निर्धारक और रखरखाव) तरीका है। –

+0

@ डाउनवॉटर: कृपया समझाएं। धन्यवाद! – jason

+0

कोड पुनरावृत्ति से बचने के संदर्भ में, निरंतर परिभाषित करना (जैसा कि नोबगज़ द्वारा सुझाया गया है) प्रतिबिंब का उपयोग करने से लगभग हमेशा बेहतर विकल्प है। ऐसे मामले हैं जहां प्रतिबिंब उचित है लेकिन कोड पुनरावृत्ति से परहेज आमतौर पर अन्य तरीकों से किया जा सकता है। उस ने कहा, प्रतिबिंब आसान हो सकता है क्योंकि इन संख्याओं में से बहुत सारे हैं। नोट: मैं डाउनवॉटर नहीं हूं। – Brian

6

ठीक है, आप पहले से ही एक जादुई संख्या संरचना घोषणा में इस्तेमाल किया। साथ ही ऐसा करते हैं हो सकता है:

private const int LfaNewOffset = 60; 

[StructLayout(LayoutKind.Explicit)] 
struct IMAGE_DOS_HEADER { 
    [FieldOffset(LfaNewOffset)] public int e_lfanew; 
} 
... 
if (n >= LfaNewOffset + sizeof(int)) { 
    ... 
} 
+0

क्या होगा यदि उसके पास संरचना की परिभाषा तक पहुंच न हो? मैं मानता हूं कि यह स्पष्ट नहीं है कि वह करता है या नहीं करता है। – jason

+0

@ जेसन: यदि वह नहीं करता है, तो यह काम नहीं करेगा। लेकिन मुझे इस विधि में एक दोष के रूप में इंगित करने की बहुत आवश्यकता नहीं है, क्योंकि यह स्वयं स्पष्ट है। – Brian

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