المستوى: مبتدئ. المقال ده هيوضّحلك ليه نفس الرقم لما تخزّنه في جهازين مختلفين أو تبعته على الشبكة ممكن يرجع بالمقلوب، وإزاي تتجنّب البَج ده بسطر واحد. مش محتاج خبرة سابقة، بس عارف يعني إيه متغير ورقم.
لو حفظت رقم في ملف على جهاز ورجعت فتحته على جهاز تاني فطلع رقم غريب تمامًا، ده غالبًا مش عطل. ده اسمه Endianness: ترتيب تخزين بايتات الرقم في الذاكرة.
المشكلة باختصار
الرقم الكبير مش بيتخزّن في خانة واحدة. بيتقسّم لبايتات (كل بايت 8 بت). السؤال: مين الأول في الذاكرة، أهم بايت ولا أقل بايت؟ الإجابة بتختلف من معالج للتاني. ده اللي بيخلّي نفس الـ 4 بايتات تتقري كرقمين مختلفين.
مثال يقرّب الفكرة: حرب البيضة في رواية جاليفر
في رواية "رحلات جاليفر"، أهل ليليبوت اتخانقوا حرب كاملة على سؤال سخيف: تكسر البيضة من الطرف العريض (Big End) ولا الطرف الرفيع (Little End). محدش منهم غلط؛ كل فريق ماشي على عادة. المهم إن الكل يتفق على طريقة واحدة عشان الأكل يمشي.
الكمبيوترات بالظبط زي كده. فيه معالجات بتبدأ التخزين من "الطرف الكبير" (أهم بايت الأول)، وفيه اللي بيبدأ من "الطرف الصغير" (أقل بايت الأول). كل واحد شغّال صح لوحده. المشكلة بس لما اتنين بترتيب مختلف يتكلموا مع بعض من غير اتفاق.
المفهوم بدقة: إيه هو الـ Endianness
خد الرقم 0x12345678 (رقم بـ 4 بايتات). البايت الأهم هو 0x12 والأقل هو 0x78. عندك ترتيبين:
- Big Endian: الأهم الأول. الترتيب في الذاكرة:
12 34 56 78. ده هو "ترتيب الشبكة" (network byte order). - Little Endian: الأقل الأول. الترتيب:
78 56 34 12. ده اللي شغّال على معالجات Intel/AMD (x86) وأغلب أجهزة ARM الحديثة.
الافتراض هنا إننا بنتكلم عن تخزين binary للأرقام الصحيحة. النصوص (UTF-8) والـ JSON مش بيتأثروا بالموضوع ده، فهتلاقيه بيظهر بس لما تتعامل مع بايتات خام.
جرّبها بنفسك: كود بايثون شغّال
الكود ده بياخد نفس الرقم ويطبع شكله بالترتيبين، وبعدين يوريك بالظبط إيه اللي بيحصل لو خلطت بينهم:
import struct, sys
n = 0x12345678
big = struct.pack(">I", n) # big endian
little = struct.pack("<I", n) # little endian
print("ترتيب جهازك :", sys.byteorder)
print("big :", big.hex(" ")) # 12 34 56 78
print("little :", little.hex(" ")) # 78 56 34 12
# لو قريت بايتات little endian كأنها big endian:
wrong = struct.unpack(">I", little)[0]
print("الرقم بعد الخلط:", hex(wrong), "=", wrong)
# 0x78563412 = 2018915346
النتيجة الملموسة: نفس الـ 4 بايتات بالظبط. لكن لما تقراهم بالترتيب الغلط، الرقم بيتحوّل من (305,419,896) لـ (2,018,915,346). فرق أكتر من مليار ونص، من غير أي رسالة خطأ. ده النوع اللي بيخدعك ساعات في الديباجينج.