2010-10-02 32 views
8

तो कल काम पर, मुझे एक एएफपी फ़ाइल में पृष्ठों की गिनती करने के लिए एक आवेदन लिखना पड़ा। तो मैंने अपने एमओ: डीसीए स्पेक पीडीएफ को धूल दिया और संरचित क्षेत्र BPG (Begin Page) और इसके 3-बाइट पहचानकर्ता को मिला। ऐप को एईक्स बॉक्स पर चलाने की जरूरत है, इसलिए मैंने इसे जावा में लिखने का फैसला किया।जावा बाइट्स को समझना

अधिकतम दक्षता के लिए, मैंने फैसला किया कि मैं प्रत्येक संरचित क्षेत्र के पहले 6 बाइट्स पढ़ूंगा और फिर क्षेत्र में शेष बाइट्स को छोड़ दूंगा। यह मैं मिलेगा:

0: Start of field byte 
1-2: 2-byte length of field 
3-5: 3-byte sequence identifying the type of field 

तो मैं फ़ील्ड प्रकार की जाँच करें और एक पेज काउंटर बढ़ाने के अगर यह BPG है, और मैं नहीं करता है, तो यह नहीं है। फिर मैं उनके माध्यम से पढ़ने के बजाय मैदान में शेष बाइट छोड़ देता हूं। और यहां, छोड़ने (और वास्तव में क्षेत्र की लंबाई में) जहां मैंने पाया कि जावा हस्ताक्षरित बाइट्स का उपयोग करता है।

मैंने कुछ googling किया और काफी उपयोगी जानकारी मिली। सबसे उपयोगी, निश्चित रूप से, हस्ताक्षर किए गए int मान प्राप्त करने के लिए थोड़ा सा &0xff करने का निर्देश था। यह मेरे लिए एक लम्बाई पाने के लिए जरूरी था जिसे बाइट्स की संख्या को छोड़ने के लिए गणना में इस्तेमाल किया जा सकता था।

अब मुझे पता है कि 128 पर, हम -128 से पीछे की ओर गिनना शुरू करते हैं। मैं क्या जानना चाहता हूं कि बिटवाई ऑपरेशन यहां कैसे काम करता है - अधिक विशेष रूप से, मैं ऋणात्मक संख्या के लिए द्विआधारी प्रतिनिधित्व पर कैसे पहुंचता हूं।

यदि मैं थोड़ा सा & ठीक से समझता हूं, तो आपका परिणाम उस संख्या के बराबर है जहां केवल आपके दो नंबरों की सामान्य बिट सेट की गई हैं। तो byte b = -128 संभालने, हम होगा:

b & 0xff // 128 

1000 0000-128 
1111 1111 255 
--------- 
1000 0000 128 

तो कैसे मैं -128 के लिए 1000 0000 पर पहुंचने होगा? मैं -72 या -64 जैसी कम स्पष्ट चीज़ों का द्विआधारी प्रतिनिधित्व कैसे प्राप्त करूं?

उत्तर

18

आदेश में एक नकारात्मक संख्या की बाइनरी प्रतिनिधित्व प्राप्त करने के लिए आपके पास दो के पूरक गणना:

  • धनात्मक संख्या की बाइनरी प्रतिनिधित्व जाओ
  • उलटें सभी बिट्स
  • जोड़े एक

चलिए एक उदाहरण के रूप में करते हैं:

0100 1000 72 
1011 0111 All bits inverted 
1011 1000 Add one 

तो -72 का बाइनरी (8-बिट) प्रतिनिधित्व 10111000 है।

वास्तव में आपके साथ क्या हो रहा है निम्न है: आपके पास फ़ाइल 10111000 के साथ एक बाइट है। जब एक हस्ताक्षरित बाइट (जो संभवतः आप चाहते हैं) के रूप में व्याख्या की जाती है, तो यह 88 है।

जावा में, जब इस बाइट को int के रूप में उपयोग किया जाता है (उदाहरण के लिए read() एक इंट, या निहित प्रचार के कारण) देता है, इसे एक हस्ताक्षरित बाइट के रूप में व्याख्या किया जाएगा, और 11111111 11111111 11111111 10111000 पर साइन-विस्तारित किया जाएगा। यह मूल्य -72 के साथ एक पूर्णांक है।

तक Anding 0xff साथ आप केवल न्यूनतम 8 बिट बनाए रखने, तो आपके पूर्णांक अब 00000000 00000000 00000000 10111000, जो 88.

+0

+1 यह उल्लेख करने के लिए कि ऑपरेशन साइन एक्सटेंशन के साथ एक int में होता है। –

+4

यह वही है जो मैं बाद में था, बहुत बहुत धन्यवाद।यही कारण है कि मैं Stackoverflow प्यार करता हूँ। –

0

बिना हस्ताक्षरित बाइट मान प्राप्त करने के लिए आप या तो कर सकते हैं।

int u = b & 0xFF; 

या

int u = b < 0 ? b + 256 : b; 
2

क्या मैं जानना चाहता हूँ कि कैसे बिटवाइज़ आपरेशन यहां काम करता है - अधिक विशेष रूप से, मैं कैसे एक ऋणात्मक संख्या के लिए द्विआधारी प्रतिनिधित्व पर पहुंचें।

ऋणात्मक संख्या का द्विआधारी प्रतिनिधित्व उस सकारात्मक संख्या की बिट-फ्लिप के साथ जोड़ा गया है। इस प्रतिनिधित्व को two's complement कहा जाता है।

1

मुझे लगता है कि यहां जादू है कि बाइट को एक बड़े कंटेनर में संग्रहीत किया जाता है, संभवतः 32 बिट int। और यदि बाइट को हस्ताक्षरित बाइट के रूप में व्याख्या किया गया था तो इसे 32 बिट int में समान संख्या का प्रतिनिधित्व करने के लिए विस्तारित किया जाता है, यह है कि बाइट का सबसे महत्वपूर्ण बिट (पहला वाला) 1 है तो 32 बिट int में सभी उस 1 के बाईं ओर स्थित बिट्स भी 1 हो गए हैं (जिस तरह नकारात्मक संख्याओं का प्रतिनिधित्व किया जाता है, दो पूरक हैं)।

अब, यदि आप & 0xFF हैं कि आप उन 1 को काटते हैं और आपके द्वारा पढ़े गए बाइट मान का प्रतिनिधित्व करने वाले "सकारात्मक" int के साथ समाप्त होते हैं।

0

बिट 7 सेट के साथ बाइट्स के लिए है:

unsigned_value = signed_value + 256 

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

1

सुनिश्चित नहीं है कि आप वास्तव में क्या चाहते हैं :) मुझे लगता है कि आप एक हस्ताक्षरित बहु-बाइट मूल्य निकालने के लिए कह रहे हैं? सबसे पहले, क्या होता है पर देखने के लिए जब आप पर हस्ताक्षर एक एकल बाइट का विस्तार:

byte[] b = new byte[] { -128 }; 
int i = b[0]; 
System.out.println(i); // prints -128! 

तो, संकेत सही ढंग से extendet 32 ​​बिट के लिए कुछ भी विशेष कर के बिना है। बाइट 1000 0000 1111 1111 1111 1111 1111 1111 1000 0000 पर सही ढंग से विस्तारित करता है। आप पहले से ही जानते हैं कि 0xFF के साथ साइन एक्सटेंशन को दबाने के लिए - बहु बाइट मानों के लिए, आप केवल सबसे महत्वपूर्ण बाइट का विस्तार करना चाहते हैं , और कम महत्वपूर्ण बाइट्स आप के रूप में अहस्ताक्षरित का इलाज करना चाहते हैं (उदाहरण मानता नेटवर्क बाइट क्रम, 16-बिट पूर्णांक मूल्य):

byte[] b = new byte[] { -128, 1 }; // 0x80, 0x01 
int i = (b[0] << 8) | (b[1] & 0xFF); 
System.out.println(i); // prints -32767! 
System.out.println(Integer.toHexString(i)); // prints ffff8001 

तुम बहुत सबसे महत्वपूर्ण एक को छोड़कर हर बाइट के हस्ताक्षर विस्तार को दबाने के लिए की जरूरत है, 64-बिट लंबे समय तक हस्ताक्षरित 32-बिट int निकालने के लिए:

byte[] b = new byte[] { -54, -2, -70, -66 }; // 0xca, 0xfe, 0xba, 0xbe 
long l = (b[0]   << 24) | 
     ((b[1] & 0xFF) << 16) | 
     ((b[2] & 0xFF) << 8) | 
     ((b[3] & 0xFF)  ); 
System.out.println(l); // prints -889275714 
System.out.println(Long.toHexString(l)); // prints ffffffffcafebabe 

नोट: इंटेल आधारित सिस्टम पर, बाइट्स हैं एन रिवर्स ऑर्डर (पहले कम से कम महत्वपूर्ण बाइट) में संग्रहीत है क्योंकि x86 आर्किटेक्चर स्मृति में इस क्रम में बड़ी इकाइयों को स्टोर करता है। बहुत सारे x86 मूल सॉफ़्टवेयर इसका उपयोग फ़ाइल स्वरूपों में भी करते हैं।

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