كيف يتم تخزين البتات في الذاكرة؟ (في قطع؟ هل يمكن أن يكون هناك أجزاء من أحجام متعددة مخزنة؟)

StackOverflow https://stackoverflow.com/questions/1546381

سؤال

اعتدت أن أعتقد أن كل موقع ذاكرة يحتوي على 8 أو 16 أو 32 أو 64 بت. لذلك سيتم تخزين 0101 في آلة 8 بتات مثل 00000101 (علامة تم تمديدها إذا كانت سلبية). كان كل هذا جيدًا وداندي حتى كتبت برنامجًا في جافا بدافع الفضول لمعرفة بعض الأعمال الداخلية لهذا النظام.

الطريقة المعنية تبدو هكذا:

public void printBinaryRep(File f){
        try{
            FileInputStream inputStream = new FileInputStream(f);
            int next = 0;
            byte b = 0;
            while((next = inputStream.read()) != -1){
                b = (byte)next;
                System.out.println((char)next + " : "+Integer.toBinaryString(next));
            }
            inputStream.close();
        }
        catch(Exception e){System.out.println(e);}
 }

حصلت على هذا الإخراج من ملف يقول مرحبًا World

H : 1001000
e : 1100101
l : 1101100
l : 1101100
o : 1101111
  : 100000
W : 1010111
o : 1101111
r : 1110010
l : 1101100
d : 1100100

كل ذلك يبدو على ما يرام باستثناء المساحة. يحتوي على 6 بت بدلاً من 8. أنا الآن أتساءل كيف يتم تخزين كل هذه المعلومات في الذاكرة. إذا تم تخزين كل ذلك في قطع 8 بت ، مثل

مرحبًا: 10010001100101110110011011001101111

ثم يمكنك ببساطة إلقاء نظرة على كل قطعة 8 بت ومعرفة الرقم الذي يمثله (ثم رمز ASCII الذي يشير إليه). كيف تعمل عندما يتم تخزين حرف مختلف الحجم (مثل مساحة 6 بت و 4 بت /ن) معهم ؟؟ ثم ألن تخزين عدد صغير في مساحة كبيرة يضيع الكثير من البتات؟

أعتقد أن لدي بعض الفهم الأساسي الخطأ (أو ربما خطأ البرنامج في مكان ما ...). آسف إذا كان السؤال يبدو غريباً أو غير معمق بشكل لا يناس. انا فقط اريد ان اعرف. لقد قمت ببعض googling ، لكنها لم تتوصل إلى أي شيء ذي صلة. إذا تمكنت من إخباري أين أخطأت أو أوجهني في الاتجاه الصحيح ، فأنا أقدر ذلك كثيرًا. شكرًا!

هل كانت مفيدة؟

المحلول

سيكون من الأفضل للتجربة في C و/أو التجميع ، بدلاً من Java. هذه اللغات منخفضة المستوى وتكشف مساحة العنوان مباشرة.

اعتدت أن أعتقد أن كل موقع ذاكرة يحتوي على 8 أو 16 أو 32 أو 64 بت. لذلك سيتم تخزين 0101 في آلة 8 بتات مثل 00000101 (علامة تم تمديدها إذا كانت سلبية). كان كل هذا جيدًا وداندي حتى كتبت برنامجًا في جافا بدافع الفضول لمعرفة بعض الأعمال الداخلية لهذا النظام.

تحتوي جميع مواقع الذاكرة في أنظمة x86 على 8 بت (1 بايت). إذا كانت القيمة تحتوي على بيانات أكثر مما يمكن أن تتناسب مع بايت واحد ، فسيتم تخزينه باستخدام بايتات متعددة. على سبيل المثال ، في C ، يتم تخزين نوع "Float" باستخدام 4 بايت (32 بت).

كل ذلك يبدو على ما يرام باستثناء المساحة. يحتوي على 6 بت بدلاً من 8. أنا الآن أتساءل كيف يتم تخزين كل هذه المعلومات في الذاكرة. إذا تم تخزين كل ذلك في قطع 8 بت ، مثل

يتم تخزين المساحة أيضًا في بايت واحد. رمز الطباعة الخاص بك ينسى أن تخرج إلى 8 مساحات. 100000 == 00100000 == 0x20.

نصائح أخرى

المساحة لديها 8 بت. إنه فقط integer.tobinarystring لا يطبع الرائدة 0 يتكون من الطريقة التي استخدمتها بها.

مع كل الرائدة 0 بت ، يبدو في الواقع هكذا في الذاكرة:

H : 01001000
e : 01100101
l : 01101100
l : 01101100
o : 01101111
  : 00100000
W : 01010111
o : 01101111
r : 01110010
l : 01101100
d : 01100100

كان الحدس الأصلي الخاص بك (في الغالب) صحيحًا: جميع مواقع الذاكرة تتكون من نفس عدد البتات. على جميع الآلات الحديثة ، هناك ثمانية بتات في "بايت" ، حيث يكون البايت هو أصغر جزء من الذاكرة التي يمكن للجهاز الوصول إليها بشكل فردي.

انظر عن كثب إلى الإخراج الخاص بك. عندك سبعة أرقام في كل منهم باستثناء الفضاء. تحدث المساحة فقط بأصفار اثنين في تمثيلها الثنائي ، بينما تبدأ الحروف الأخرى بواحدة.

في الواقع نهجك خاطئ. الترميز مهم جدا هنا.

إذا كنت تستخدم ASCII ، فيمكنك بسهولة القول إن كل حرف يتم تخزينه في بايت (ثمانية بتات) ولكن عند تشفير التغييرات ، لا يمكنك قول ذلك.

على سبيل المثال: يستخدم UTF-8 واحد إلى ثلاثة بايت (من 8 إلى 24 بت) لكل حرف على سلسلة. هذا هو السبب في أنك سترى حمولة زائدة يمكنك من خلالها تحديد التشفير على كائن inputstream.

اختيار دفق الإدخال الخاطئ سيؤدي تمامًا إلى إخراج سلسلة خاطئ. وبالتالي عليك أن تعرف ترميز الملف لفهم البت الذي يعني ماذا. في الواقع fileInputStream يفعل هذا لك.

إذا قمت بتخزين رقم كسلسلة ، فستستغرق طولًا في القرص الصلب. تماما مثل شخصية أخرى.

ومع ذلك ، إذا قمت بتخزين 123456789 كسلسلة مع ترميز ASCII ، فسوف يستغرق الأمر 9*8 بت = 72 بت.

إذا قمت بتخزين هذا على أنه عدد صحيح ، (لاحظ أن عرض بيانات Integer يختلف في بيئات مختلفة) ، فسيستغرق الأمر فقط 16 بت.

كما لا يمكنك التأكد من ذلك

H : 01001000
e : 01100101
l : 01101100
l : 01101100
o : 01101111
  : 00100000
W : 01010111
o : 01101111
r : 01110010
l : 01101100
d : 01100100
\n: 00001010

يتم تخزينها في القرص الصلب كما H: 01001000 E: 01100101 L: 01101100 L: 01101100 O: 01101111: 00100000 W: 01010111 O: 01101111 R: 01110010 L: 01101100 D: 01100100 n: 0000101010101010

لا يمكنك التأكد من ذلك. نظام الملفات ليس بهذه البساطة. ربما يكون مرحبًا متتاليًا ولكن سلسلة العالم في نهاية محرك الأقراص. لهذا السبب هناك أمر defrag.

ولكن إذا تحدثنا عن الذاكرة الرئيسية (ذاكرة الوصول العشوائي) عندما تحدد سلسلة ، أتوقع أن تكون البتات متتالية. على الأقل في ج هو. يمكنك تحديد سلسلة من هذا القبيل.

char[100] value; // c is a char array. (there is no string type in c)

هنا القيمة [0] هي الحرف الأول لسلسلة لدينا. والقيمة العناوين فقط إلى موقع صفائف char في الذاكرة.

إذا كان عنوان Value [0] هو 10 ، فإن عنوان القيمة [1] هو 10+8 = 18.

يمكن مقارنة أرقام متاجر أجهزة الكمبيوتر بمقياس عداد المسافات في السيارة. إذا كان عداد المسافات لديه 4 أرقام ، فإنه يخزن الرقم 33 كـ "0033".

اذا كان شخص ما يطلب أنت ما هو مسافة الأميال الخاصة بك ، لن تقول "صفر ألف صفر مائة وثلاثين". بشكل افتراضي ، جافا لا. (على الرغم من أنه يمكنك إخباره.)

ثم ألن تخزين عدد صغير في مساحة كبيرة يضيع الكثير من البتات؟

حسنا ، ليس حقا. لنفترض أنه كان لديك 11000100 في الذاكرة في مكان ما. كيف من المفترض أن يعرف الكمبيوتر ما إذا كان هذا يعني 11000100 ، أو 11000 متبوعًا بـ 100 ، أو 1 متبوعًا 1000 متبوعًا بـ 100 ، وهكذا؟

حسنًا ، في الواقع ، يتبع الكمبيوتر فقط البرنامج الذي يتم إعطاؤه (تذكر أن برنامج Java يتم إنشاؤه جزئيًا من قِبل الأشخاص الذين يقومون بتصميم Java). إذا تمكنت من إنشاء نظام قابل للتطبيق لحفظ البتات ، فيمكنك جعل الكمبيوتر يفعل ذلك.

ومع ذلك ، ضع في اعتبارك أن هناك مفاضلة من حيث استخدام المعالج وصعوبة البرمجة. نظرًا لأن الكمبيوتر النموذجي يمكنه العمل مع البايتات كثير أسرع مما يمكن أن يقول ، أرقام 7 بت أو متغيرة بت ، تخزين رموز ASCII في بايت هو خيار شائع للغاية لتخزين النص.

لكن دعني أعود إلى سؤالك.

ثم ألن تخزين عدد صغير في مساحة كبيرة يضيع الكثير من البتات؟

من الناحية الرياضية ، لا. ودعا فرع من الرياضيات نظرية المعلومات يخبرنا أن عدد البتات الضرورية للغاية يعتمد على الإمكانيات التي تريد تشفيرها ومدى احتمال كل منها.

لنفترض أن لديك فقط أبجدية من أربعة أحرف (A ، B ، C ، D) ، ونستخدم أرقام ثنائية البت (00 ، 01 ، 10 ، 11 على التوالي) لتمثيلها. إذا كان كل من هذه الحروف محتملة على قدم المساواة ، فإن الحد الأدنى لعدد البتات المطلوبة لكل حرف (في المتوسط) هو 2. وبعبارة أخرى ، هناك رقم البتات الضائعة على الرغم من أن A 00 و B هو 01.

من ناحية أخرى ، إذا كنت تستخدم ASCII وتشفير A ، B ، C ، D كأرقام 7 بت التالية:

A: 1000001
B: 1000010
C: 1000011
D: 1000100

ثم تقوم "بإهدار" 5 بتات لكل حرف (على الرغم من أنك لا "تخزين أعداد صغيرة في مساحة بت كبيرة").

تعتبر هذه الأنواع من الاعتبارات مهمة عند تصميم خوارزميات الضغط ، وليست مهمة جدًا لتطبيقات Everday. من المهم بالتأكيد فهم البتات والبايت إذا كنت ترغب في تعلم C.

بحسب ال Java 4 API,

قيمة عدد صحيح غير موقّعة هي الوسيطة بالإضافة إلى 232 إذا كانت الوسيطة سلبية ؛ وإلا فإنه يساوي الحجة. يتم تحويل هذه القيمة إلى سلسلة من أرقام ASCII في الثنائي (القاعدة 2) مع عدم وجود 0S الرائدة الإضافية.

في الواقع ، تخزين البيانات هو في الواقع أكثر تعقيدًا. بالنسبة للكفاءة في المعالجة ، يتم تخزين معظم أنواع البيانات في محافظات الكلمات ، مما يعني 4 بايت على آلات 32 بت ، أو 8 بايت على آلات 64 بت. قد يتم تعبئة المصفوفات عن كثب ، لذلك char [4] قد ينتهي الأمر باستخدام نفس كمية "المساحة الفعلية" مثل char.

Java هي جهاز افتراضي ، ولست متأكدًا من بنية الذاكرة ، إن وجدت ، التي يستخدمها.

هذا يزيلها. كانت مشكلتي الرئيسية هي أنني كنت أطل على الأصفار في البداية. كنت أجرب هذا بينما كنت أقرأ المزيد عن خوارزميات الضغط (وهي GZIP) كنت أفترض ASCII على كل هذا. لم يكن رؤية التمثيل هو الهدف من البرنامج ، لكن العدد المختلفة من البتات لكل كلمة ألقاه من الهدف الأصلي المتمثل في تنفيذ ضغط أساسي يعتمد على الفهرس لنوع الملف الذي أعمل عليه. سأحاول إعادة كتابته في C بمجرد أن يكون لدي دليل على المفهوم في Java.

شكرًا!

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/integer.html#tobinary٪28int٪29
يقرأ مواصفات integer.tobinary:

"يتم تحويل هذه القيمة إلى سلسلة من أرقام ASCII في الثنائي (القاعدة 2) مع عدم وجود 0S EDIVE LEGAND"

إن التغاضي عن هذه الحقيقة هو ما أدى إلى ارتباكك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top