محاذاة بنية البيانات
محاذاة بنية البيانات هي الطريقة التي يتم بها ترتيب البيانات والوصول إليها في ذاكرة الحاسوب . وهي تتكون من ثلاث قضايا منفصلة ولكنها مترابطة: محاذاة البيانات ، وحشو بنية البيانات ، والتعبئة .
تُجري وحدة المعالجة المركزية في أجهزة الحاسوب الحديثة عمليات القراءة والكتابة إلى الذاكرة بكفاءة عالية عندما تكون البيانات مُحاذية بشكل طبيعي ، ما يعني عمومًا أن عنوان الذاكرة الخاص بالبيانات هو مُضاعف لحجمها. على سبيل المثال، في بنية 32 بت، قد تكون البيانات مُحاذية إذا تم تخزينها في أربعة بايتات متتالية، وكان البايت الأول يقع على حد فاصل 4 بايتات.
محاذاة البيانات هي عملية ترتيب العناصر وفقًا لترتيبها الطبيعي. ولضمان هذه المحاذاة، قد يكون من الضروري إضافة بعض المساحة الفارغة بين عناصر البنية أو بعد العنصر الأخير منها. على سبيل المثال، في جهاز 32 بت، يمكن إضافة 16 بت من المساحة الفارغة بين قيمة 16 بت متبوعة بقيمة 32 بت في بنية بيانات تحتوي على قيمة 16 بت متبوعة بقيمة 32 بت، وذلك لمحاذاة قيمة 32 بت مع حدود 32 بت. بدلاً من ذلك، يمكن ضغط البنية وحذف المساحة الفارغة، مما قد يؤدي إلى إبطاء الوصول، ولكنه يوفر 16 بت من الذاكرة.
على الرغم من أن محاذاة بنية البيانات تُعدّ مسألة أساسية لجميع الحواسيب الحديثة، فإن العديد من لغات البرمجة وتطبيقاتها تتعامل مع محاذاة البيانات تلقائيًا. تسمح لغات مثل فورتران ، وآدا ، [ 1 ] [ 2 ]، وبي إل/آي ، [ 3 ] ، وباسكال ، [ 4 ] وبعض تطبيقات لغتي سي وسي++، ودي ، [ 5 ] ، وراست ، [ 6 ] ، وسي شارب ، [ 7 ]، ولغة التجميع، بالتحكم الجزئي على الأقل في حشو بنية البيانات، وهو ما قد يكون مفيدًا في بعض الحالات الخاصة.
التعريفات
يُقال إن عنوان الذاكرة a مُحاذي لـ n بايت عندما يكون a من مضاعفات n (حيث n قوة للعدد 2). في هذا السياق، البايت هو أصغر وحدة للوصول إلى الذاكرة، أي أن كل عنوان ذاكرة يُحدد بايتًا مختلفًا. يحتوي العنوان المُحاذي لـ n بايت على أقل من log 2 ( n ) من الأصفار الأقل أهمية عند التعبير عنه بالنظام الثنائي .
يشير التعبير البديل b-bit aligned إلى عنوان محاذي لـ b/8 بايت (على سبيل المثال، 64-bit aligned هو 8 بايت محاذي).
يُقال إن عملية الوصول إلى الذاكرة مُحاذية عندما يكون طول البيانات التي يتم الوصول إليها n بايت، ويكون عنوان البيانات مُحاذيًا لـ n بايت. أما إذا لم تكن عملية الوصول إلى الذاكرة مُحاذية، فيُقال إنها غير مُحاذية . تجدر الإشارة إلى أن عمليات الوصول إلى الذاكرة على مستوى البايت تكون مُحاذية دائمًا بحكم تعريفها.
يُقال إن مؤشر الذاكرة الذي يشير إلى بيانات أولية بطول n بايت مُحاذي إذا كان مسموحًا له فقط باحتواء عناوين مُحاذية لـ n بايت، وإلا يُقال إنه غير مُحاذي . أما مؤشر الذاكرة الذي يشير إلى مجموعة بيانات (بنية بيانات أو مصفوفة) فيُقال إنه مُحاذي إذا (وفقط إذا) كانت كل بيانات أولية في المجموعة مُحاذية.
لاحظ أن التعريفات المذكورة أعلاه تفترض أن كل قيمة بيانات أولية هي قوة من قوى العدد اثنين بايت. عندما لا يكون هذا هو الحال (كما هو الحال مع الفاصلة العائمة 80 بت على معالجات x86 )، فإن السياق يؤثر على الشروط التي تُعتبر فيها البيانات مُحاذية أم لا.
يمكن تخزين هياكل البيانات في الذاكرة على المكدس بحجم ثابت يُعرف باسم المحدود أو على الكومة بحجم ديناميكي يُعرف باسم غير المحدود .
مشاكل
تصل وحدة المعالجة المركزية إلى الذاكرة بكلمة واحدة في كل مرة. طالما أن حجم كلمة الذاكرة لا يقل عن حجم أكبر نوع بيانات أساسي يدعمه الحاسوب، فإن عمليات الوصول المتوافقة ستصل دائمًا إلى كلمة ذاكرة واحدة. قد لا ينطبق هذا على عمليات الوصول غير المتوافقة.
إذا لم تكن أعلى وأدنى بايتات البيانات ضمن نفس كلمة الذاكرة، يجب على الحاسوب تقسيم الوصول إلى البيانات إلى عدة عمليات وصول إلى الذاكرة. يتطلب هذا دوائر معقدة لتوليد عمليات الوصول إلى الذاكرة وتنسيقها. ولمعالجة حالة وجود كلمات الذاكرة في صفحات ذاكرة مختلفة، يجب على المعالج إما التحقق من وجود كلتا الصفحتين قبل تنفيذ التعليمات، أو أن يكون قادرًا على معالجة خطأ في ذاكرة الترجمة السريعة (TLB) أو خطأ في الصفحة عند أي عملية وصول إلى الذاكرة أثناء تنفيذ التعليمات.
تتجنب بعض تصميمات المعالجات عمدًا إدخال هذا التعقيد، وتُقدم بدلاً من ذلك سلوكًا بديلاً في حالة الوصول غير المُحاذي للذاكرة. على سبيل المثال، تتطلب تطبيقات معمارية ARM قبل ARMv6 ISA الوصول المُحاذي للذاكرة إلزاميًا لجميع تعليمات التحميل والتخزين متعددة البايتات. [ 8 ] اعتمادًا على التعليمات المُحددة التي تم إصدارها، قد تكون نتيجة محاولة الوصول غير المُحاذي هي تقريب البتات الأقل أهمية في العنوان المُخالف إلى الأسفل لتحويله إلى وصول مُحاذي (مع بعض التحفظات الإضافية أحيانًا)، أو إطلاق استثناء MMU (إذا كانت وحدة MMU موجودة)، أو التسبب بصمت في نتائج أخرى قد تكون غير متوقعة. تدعم معمارية ARMv6 وما بعدها الوصول غير المُحاذي في العديد من الحالات، ولكن ليس بالضرورة في جميعها.
عند الوصول إلى كلمة ذاكرة واحدة، تكون العملية ذرية، أي تُقرأ أو تُكتب كلمة الذاكرة بأكملها دفعة واحدة، ويتعين على الأجهزة الأخرى الانتظار حتى اكتمال عملية القراءة أو الكتابة قبل أن تتمكن من الوصول إليها. قد لا ينطبق هذا على عمليات الوصول غير المتوافقة إلى كلمات ذاكرة متعددة، على سبيل المثال، قد يقرأ جهاز الكلمة الأولى، ويكتب جهاز آخر الكلمتين، ثم يقرأ الجهاز الأول الكلمة الثانية، بحيث لا تكون القيمة المقروءة هي القيمة الأصلية ولا القيمة المُحدثة. على الرغم من ندرة هذه الأعطال، إلا أنه يصعب تحديدها.
حشو بنية البيانات
على الرغم من أن المترجم (أو المفسر ) عادةً ما يخصص عناصر البيانات الفردية على حدود متطابقة، إلا أن هياكل البيانات غالبًا ما تحتوي على عناصر ذات متطلبات محاذاة مختلفة. وللحفاظ على المحاذاة الصحيحة، يُدرج المترجم عادةً عناصر بيانات إضافية غير مُسماة بحيث تتم محاذاة كل عنصر بشكل صحيح. بالإضافة إلى ذلك، قد يتم إضافة عنصر نهائي غير مُسمى إلى هيكل البيانات ككل. وهذا يسمح بمحاذاة كل عنصر من عناصر مصفوفة الهياكل بشكل صحيح.
لا تُضاف الحشوة إلا عندما يتبع عنصر هيكلي عنصر آخر ذو متطلبات محاذاة أكبر، أو في نهاية الهيكل. بتغيير ترتيب العناصر في الهيكل، يُمكن تغيير مقدار الحشوة المطلوبة للحفاظ على المحاذاة. على سبيل المثال، إذا رُتبت العناصر تنازليًا حسب متطلبات المحاذاة، فإن الحد الأدنى من الحشوة المطلوبة يكون دائمًا أقل من أكبر متطلبات محاذاة في الهيكل. أما حساب الحد الأقصى للحشوة المطلوبة فهو أكثر تعقيدًا، ولكنه دائمًا أقل من مجموع متطلبات المحاذاة لجميع العناصر مطروحًا منه ضعف مجموع متطلبات المحاذاة لنصف العناصر الأقل محاذاة في الهيكل.
على الرغم من أن لغتي C و C++ لا تسمحان للمترجم بإعادة ترتيب عناصر البنية لتوفير المساحة، إلا أن لغات أخرى قد تسمح بذلك. كما يُمكن توجيه معظم مترجمات C و C++ لـ"تجميع" عناصر البنية إلى مستوى معين من المحاذاة، على سبيل المثال، "pack(2)" تعني محاذاة عناصر البيانات الأكبر من بايت واحد إلى حد بايتين بحيث لا يتجاوز طول أي عناصر حشو بايتًا واحدًا. وبالمثل، في لغة PL/I، يُمكن تعريف بنية UNALIGNEDلإزالة جميع الحشو باستثناء الحشو حول سلاسل البتات.
يُستخدم هذا النوع من الهياكل "المُكدسة" في توفير الذاكرة. فعلى سبيل المثال، يتطلب هيكل يحتوي على بايت واحد (مثل `a` char) وعدد صحيح من أربعة بايتات (مثل `n` uint32_t) ثلاثة بايتات إضافية للحشو. يستهلك مصفوفة كبيرة من هذه الهياكل ذاكرة أقل بنسبة 37.5% إذا كانت مُكدسة، مع العلم أن الوصول إلى كل هيكل قد يستغرق وقتًا أطول. يُمكن اعتبار هذا الحل الوسط نوعًا من المفاضلة بين المساحة والوقت .
على الرغم من أن استخدام البنى "المضغوطة" يُستخدم غالبًا لتوفير مساحة الذاكرة ، إلا أنه يُمكن استخدامه أيضًا لتهيئة بنية البيانات للإرسال باستخدام بروتوكول قياسي. مع ذلك، في هذه الحالة، يجب الحرص على تخزين قيم عناصر البنية وفقًا لترتيب البايتات المطلوب في البروتوكول (غالبًا ترتيب بايتات الشبكة )، والذي قد يختلف عن ترتيب البايتات المستخدم أصلاً في الجهاز المضيف.
حشو الحوسبة
توفر الصيغ التالية عدد بايتات الحشو المطلوبة لمحاذاة بداية بنية البيانات (حيث mod هو عامل باقي القسمة ):
الحشو = (المحاذاة - (الإزاحة mod المحاذاة)) mod المحاذاة محاذاة = إزاحة + حشو = الإزاحة + ((المحاذاة - (الإزاحة mod المحاذاة)) mod المحاذاة)
على سبيل المثال، الحشو الذي يجب إضافته إلى الإزاحة 0x59d لبنية محاذية من 4 بايت هو 3. ستبدأ البنية عند 0x5a0، وهو مضاعف للعدد 4. ومع ذلك، عندما تكون محاذاة الإزاحة مساوية بالفعل لمحاذاة المحاذاة ، فإن باقي القسمة الثاني في (محاذاة - (إزاحة باقي القسمة محاذاة)) باقي القسمة محاذاة محاذاة سيعيد صفرًا، وبالتالي تبقى القيمة الأصلية دون تغيير.
بما أن المحاذاة هي بحكم تعريفها قوة العدد اثنين، [ أ ] يمكن اختزال عملية باقي القسمة إلى عملية AND على مستوى البت .
تُنتج الصيغ التالية القيم الصحيحة (حيث & هي عملية AND ثنائية و ~ هي عملية NOT ثنائية ) - بشرط أن يكون الإزاحة غير مُوقّع أو أن يستخدم النظام حساب المتمم الثنائي :
الحشو = (المحاذاة - (الإزاحة & (المحاذاة - 1))) & (المحاذاة - 1) = -offset & (align - 1) aligned = (offset + (align - 1)) & ~(align - 1) = (الإزاحة + (المحاذاة - 1)) & -محاذاة
محاذاة نموذجية لهياكل C على x86
يتم تخزين عناصر بنية البيانات بشكل متسلسل في الذاكرة، بحيث في البنية أدناه، data1سيسبق العنصر دائمًا data2؛ data2وسيسبق دائمًا data3:
struct MyData { short data1 ; short data2 ; short data3 ; };إذا تم تخزين النوع shortفي بايتين من الذاكرة، فسيكون كل عنصر من عناصر بنية البيانات الموضحة أعلاه محاذيًا لبايتين. data1سيكون العنصر الأول عند الإزاحة 0، والثاني data2عند الإزاحة 2، والثالث data3عند الإزاحة 4. سيكون حجم هذه البنية 6 بايتات.
عادةً ما يكون لنوع كل عنصر من عناصر البنية محاذاة افتراضية، ما يعني أنه سيتم محاذاته على حدود محددة مسبقًا ما لم يطلب المبرمج خلاف ذلك. المحاذاة النموذجية التالية صالحة للمترجمات من مايكروسوفت ( Visual C++ )، وبورلاند / كود جير ( C++Builder )، وديجيتال مارس (DMC)، وجنو ( GCC ) عند الترجمة لأنظمة x86 ذات 32 بت:
charسيتم محاذاة بايت واحد ( A ) إلى بايت واحد.- سيتم محاذاة A
short(بايتين) إلى بايتين. intسيتم محاذاة (أربعة بايتات) إلى أربعة بايتات .longسيتم محاذاة A (أربعة بايتات) إلى أربعة بايتات.floatسيتم محاذاة A (أربعة بايتات) إلى أربعة بايتات.doubleسيتم محاذاة A (ثمانية بايتات) إلى 8 بايتات على نظام التشغيل Windows و 4 بايتات على نظام التشغيل Linux (8 بايتات مع خيار وقت التجميع -malign-double ).long longسيتم محاذاة A (ثمانية بايتات) إلى 8 بايتات على نظام التشغيل Windows و 4 بايتات على نظام التشغيل Linux (8 بايتات مع خيار وقت التجميع -malign-double ).- A
long double(عشرة بايتات مع C++Builder و DMC، ثمانية بايتات مع Visual C++، اثنا عشر بايتًا مع GCC) ستكون محاذية لـ 8 بايتات مع C++Builder، و2 بايت مع DMC، و8 بايتات مع Visual C++، و4 بايتات مع GCC. - أي مؤشر (أربعة بايتات) سيكون محاذيًا لأربعة بايتات. (مثال:
char*,int*)
الاختلافات الملحوظة الوحيدة في محاذاة نظام LP64 ذي 64 بت عند مقارنته بنظام 32 بت هي:
longسيتم محاذاة A (ثمانية بايتات) إلى 8 بايتات.doubleسيتم محاذاة A (ثمانية بايتات) إلى 8 بايتات.long longسيتم محاذاة A (ثمانية بايتات) إلى 8 بايتات.- A
long double(ثمانية بايتات مع Visual C++، وستة عشر بايتًا مع GCC) ستكون محاذية لثمانية بايتات مع Visual C++ ومحاذية لستة عشر بايتًا مع GCC. - أي مؤشر (ثمانية بايتات) سيكون محاذيًا لثمانية بايتات.
تعتمد بعض أنواع البيانات على طريقة التنفيذ.
إليكم بنية بيانات تحتوي على عناصر من أنواع مختلفة، ويبلغ حجمها الإجمالي 8 بايت قبل التجميع:
struct MixedData { char c1 ; short s ; int i ; char c2 ; };بعد عملية التجميع، سيتم إضافة بايتات حشو إلى بنية البيانات لضمان محاذاة مناسبة لكل عنصر من عناصرها:
// بعد التجميع في جهاز x86 ذي 32 بت، بنية MixedData { char c1 ; // بايت واحد// بايت واحد لمحاذاة السلسلة القصيرة التالية على حد بايتين // بافتراض أن عنوان بداية البنية عدد زوجي char padding1 [ 1 ]; short s ; // بايتان int i ; // 4 بايتات - أكبر عنصر في البنية char c2 ; // بايت واحد char padding2 [ 3 ]; // 3 بايتات لجعل الحجم الإجمالي للبنية 12 بايتًا };يبلغ حجم البنية بعد التجميع الآن 12 بايت.
يتم إضافة عدد البايتات المطلوبة إلى العضو الأخير بحيث يكون الحجم الإجمالي للهيكل مضاعفًا لأكبر محاذاة لأي عضو من أعضاء الهيكل ( alignof(int) في هذه الحالة، والتي تساوي 4 على linux-32bit/gcc) .
في هذه الحالة ، تتم إضافة 3 بايتات إلى العضو الأخير لتوسيع البنية إلى حجم 12 بايت ( alignof(int) * 3 ).
struct FinalPad { float x ; char n [ 1 ]; };في هذا المثال، الحجم الإجمالي للبنية sizeof (FinalPad) == 8 ، وليس 5 (بحيث يكون الحجم من مضاعفات 4 ( alignof(float) ) ).
بناء FinalPadShort { قصيرة ; شار ن [ 3 ]؛ };في هذا المثال، الحجم الإجمالي للبنية sizeof (FinalPadShort) == 6 ، وليس 5 (ولا 8 أيضًا) (بحيث يكون الحجم من مضاعفات 2 ( alignof(short) == 2 على linux-32bit/gcc)).
من الممكن تغيير محاذاة الهياكل لتقليل الذاكرة التي تتطلبها (أو لتتوافق مع تنسيق موجود) عن طريق إعادة ترتيب أعضاء الهيكل أو تغيير محاذاة المترجم (أو "تعبئة") أعضاء الهيكل.
// بعد إعادة ترتيب بنية MixedData { char c1 ; char c2 ; short s ; int i ; };أصبح حجم البنية بعد التجميع مطابقًا لحجمها قبل التجميع، وهو 8 بايتات . لاحظ أنه تم استبدال padding1[1] (وبالتالي حذفه) بـ data4 ، ولم يعد padding2 [3] ضروريًا لأن البنية مُحاذية بالفعل لحجم كلمة طويلة.
إن الطريقة البديلة لفرض محاذاة بنية البيانات المختلطة إلى حد بايت واحد ستؤدي إلى قيام المعالج المسبق بتجاهل المحاذاة المحددة مسبقًا لأعضاء البنية، وبالتالي لن يتم إدراج أي بايتات حشو.
على الرغم من عدم وجود طريقة قياسية لتحديد محاذاة عناصر البنية (مع أن لغتي C و C++ تسمحان باستخدام مُحدِّد alignas لهذا الغرض، إلا أنه يُستخدم فقط لتحديد محاذاة أكثر دقة)، فإن بعض المُصرِّفات تستخدم توجيهات #pragma لتحديد التعبئة داخل ملفات المصدر. إليك مثال:
#pragma pack(push) // دفع المحاذاة الحالية إلى المكدس #pragma pack(1) // ضبط المحاذاة على حد بايت واحدstruct MyPackedData { char c1 ; long l ; char c2 ; };#pragma pack(pop) // استعادة المحاذاة الأصلية من المكدسيبلغ حجم هذا الهيكل بعد تجميعه 6 بايتات على نظام 32 بت. تتوفر التوجيهات المذكورة أعلاه في مُجمِّعات البرامج من مايكروسوفت [ 9 ] ، وبورلاند ، وجنو [ 10 ] ، وغيرها الكثير.
مثال آخر:
struct MyPackedData { char c1 ; long l ; char c2 ; } __attribute__ (( packed ));التعبئة الافتراضية و #pragma pack
في بعض مُجمِّعات مايكروسوفت، وخاصةً لمعالجات RISC، توجد علاقة غير متوقعة بين التعبئة الافتراضية للمشروع (التوجيه /Zp) وتوجيه #pragma pack . يُستخدم توجيه #pragma pack فقط لتقليل حجم تعبئة بنية ما عن حجم التعبئة الافتراضي للمشروع. [ 11 ] يؤدي هذا إلى مشاكل في التوافق مع رؤوس المكتبات التي تستخدم، على سبيل المثال، #pragma pack(8) ، إذا كان حجم تعبئة المشروع أصغر من ذلك. لهذا السبب، فإن ضبط حجم تعبئة المشروع على أي قيمة أخرى غير القيمة الافتراضية البالغة 8 بايت سيؤدي إلى تعطيل توجيهات #pragma pack المستخدمة في رؤوس المكتبات، مما ينتج عنه عدم توافق ثنائي بين البنى. لا يوجد هذا القيد عند التجميع لمعالجات x86.
تخصيص الذاكرة المحاذية لخطوط التخزين المؤقت
من المفيد تخصيص الذاكرة بحيث تتوافق مع أسطر ذاكرة التخزين المؤقت . إذا تم تقسيم مصفوفة ليتم معالجتها بواسطة أكثر من خيط، فإن عدم توافق حدود المصفوفة الفرعية مع أسطر ذاكرة التخزين المؤقت قد يؤدي إلى تراجع الأداء. إليك مثال لتخصيص ذاكرة (مصفوفة من نوع double بحجم 10) متوافقة مع ذاكرة تخزين مؤقت بحجم 64 بايت.
#include <stdlib.h>// إنشاء مصفوفة بحجم 10 double * foo ( void ) { double * a ; if ( posix_memalign (( void ** ) &a a إذا كان ( 64 , 10 * sizeof ( double )) == 0 ) { return a ; }return NULL ; }أهمية متطلبات المحاذاة على مستوى الأجهزة
يمكن أن تؤثر مخاوف المحاذاة على مناطق أكبر بكثير من بنية C عندما يكون الغرض هو رسم خرائط فعالة لتلك المنطقة من خلال آلية ترجمة عناوين الأجهزة (إعادة تعيين PCI، تشغيل MMU ).
على سبيل المثال، في نظام تشغيل 32 بت ، لا تُمثل الصفحة التي يبلغ حجمها 4 كيلوبايت (4096 بايت) مجرد كتلة بيانات عشوائية بحجم 4 كيلوبايت، بل هي عادةً منطقة من الذاكرة مُحاذية على حدود 4 كيلوبايت. والسبب في ذلك هو أن محاذاة الصفحة على حدود بحجمها تُمكّن الجهاز من ربط عنوان افتراضي بعنوان فعلي عن طريق استبدال البتات العليا في العنوان، بدلاً من إجراء عمليات حسابية معقدة.
مثال: لنفترض أن لدينا ربطًا في ذاكرة الترجمة السريعة (TLB) بين العنوان الظاهري 0x2CFC7000 والعنوان الفيزيائي 0x12345000 . (لاحظ أن كلا العنوانين محاذيان عند حدود 4 كيلوبايت). يؤدي الوصول إلى البيانات الموجودة في العنوان الظاهري va=0x2CFC7ABC إلى قيام ذاكرة الترجمة السريعة (TLB) بتحويل 0x2CFC7 إلى 0x12345 ، مما يتيح الوصول الفيزيائي إلى {{{1}}} . لحسن الحظ، يتطابق تقسيم 20/12 بت مع التمثيل الست عشري المقسم عند 5/3 أرقام. يمكن للأجهزة تنفيذ هذا التحويل ببساطة عن طريق دمج أول 20 بت من العنوان الفيزيائي ( 0x12345 ) مع آخر 12 بت من العنوان الظاهري ( 0xABC ). يُشار إلى هذا أيضًا باسم "الفهرسة الظاهرية ( ABC ) والوسم الفيزيائي ( 12345 )".
تحتوي كتلة البيانات ذات الحجم 2 (n+1) − 1 دائمًا على كتلة فرعية واحدة بحجم 2 n محاذية على 2 n بايت.
هكذا يمكن استخدام مُخصِّص ديناميكي لا يعرف شيئًا عن المحاذاة لتوفير مخازن مؤقتة محاذية، على حساب فقدان مساحة بمقدار الضعف.
// مثال: الحصول على 4096 بايت محاذية على مخزن مؤقت بحجم 4096 بايت باستخدام malloc()// مؤشر غير محاذٍ لمنطقة كبيرة void * up = malloc (( 1 << 13 ) - 1 ); // مؤشر محاذٍ جيدًا إلى 4 كيلوبايت void * ap = ALIGN_TO_NEXT ( up , 12 );حيث تعمل هذه الطريقة عن طريق إضافة زيادة مُحاذية، ثم مسح البتات الأقل أهمية . أحد التطبيقات الممكنة هوALIGN_TO_NEXT(p, r)rp
// افترض أن `uint32_t p, bits;` لسهولة القراءة #define ALIGN_TO(p, bits) (((p) >> bits) << bits) #define ALIGN_TO_NEXT(p, bits) ALIGN_TO(((p) + (1 << bits) - 1), bits)ملحوظات
- ↑ في أجهزة الكمبيوتر الحديثة حيث يكون محاذاة الهدف قوة للعدد اثنين. قد لا يكون هذا صحيحًا، على سبيل المثال، في نظام يستخدم بايتات 9 بت أو كلمات 60 بت.
مراجع
- ↑ "بنود تمثيل لغة آدا وقواعدها" . وثائق دليل مرجع GNAT 7.4.0w . تم الاطلاع عليه بتاريخ 30 أغسطس 2015 .
- ↑ "F.8 بنود التمثيل". دليل مبرمج لغة آدا لمترجم SPARCompiler (ملف PDF) . تم الاطلاع عليه بتاريخ 30 أغسطس 2015 .
- ↑ مواصفات لغة PL/I لنظام التشغيل IBM System/360 (ملف PDF) . IBM . يوليو 1966. الصفحات 55-56 . C28-6571-3.
- ↑ نيكلاوس ويرث (يوليو 1973). "لغة البرمجة باسكال (تقرير منقح)" (ملف PDF) . ص 12.
- ↑ "السمات - لغة البرمجة D: سمة المحاذاة" . تم الاطلاع عليه بتاريخ 13-04-2012 .
- ↑ "مخطوطة راستونوميكون - تمثيلات بديلة" . تم الاطلاع عليه بتاريخ 19-06-2016 .
- ↑ "LayoutKind Enum (System.Runtime.InteropServices)" . docs.microsoft.com . تم الاطلاع عليه بتاريخ 2019-04-01 .
- ↑ كوروسا، ليفينتي (27-12-2016). "الحالة الغريبة للوصول غير المتوافق على معالجات ARM" . ميديوم . تم الاسترجاع في 7-08-2019 .
- ↑ حزمة
- ↑ 6.58.8 تعليمات التعبئة الهيكلية
- ↑ "العمل مع هياكل التعبئة" . مكتبة MSDN . مايكروسوفت. 9 يوليو 2007. تم الاطلاع عليه بتاريخ 11 يناير 2011 .
للمزيد من القراءة
- براينت، راندال إي .؛ ديفيد، أوهالارون (2003). أنظمة الحاسوب: منظور المبرمج ( طبعة 2003). أبر سادل ريفر، نيو جيرسي، الولايات المتحدة الأمريكية: بيرسون إديوكيشن . ISBN 0-13-034074-X.
- "1. مقدمة: محاذاة القطاعات". أدوات عائلة 8086 - دليل المستخدم لأنظمة التطوير القائمة على معالجات 8080/8085 (ملف PDF) . المراجعة E (A620/5821 6K DD ed.). سانتا كلارا، كاليفورنيا، الولايات المتحدة الأمريكية: شركة إنتل . مايو 1982 [1980، 1978]. الصفحات 1-6، 3-5. رقم الطلب: 9800639-04. مؤرشف (PDF) من الأصل بتاريخ 29-02-2020 . تم الاسترجاع بتاريخ 29-02-2020 .
[...] يمكن أن يحتوي القطاع على سمة محاذاة واحدة (واثنتين في حالة سمة inpage) من أصل خمس سمات: [...] بايت، مما يعني أنه يمكن وضع القطاع في أي عنوان. [...] كلمة، مما يعني أنه لا يمكن وضع القطاع إلا في عنوان من مضاعفات العدد اثنين، بدءًا من العنوان 0H. […] فقرة، مما يعني أنه لا يمكن وضع المقطع إلا في عنوان من مضاعفات العدد 16، بدءًا من العنوان 0. […] صفحة، مما يعني أنه لا يمكن وضع المقطع إلا في عنوان من مضاعفات العدد 256، بدءًا من العنوان 0. […] داخل الصفحة، مما يعني أنه يمكن وضع المقطع في أي من السمات السابقة التي تنطبق، بالإضافة إلى ضرورة وضعه بحيث لا يتجاوز حدود الصفحة. […] رموز المحاذاة هي: […] B – بايت […] W – كلمة […] G – فقرة […] xR – داخل الصفحة […] P – صفحة […] A – مطلق […] يمكن أن يكون x في رمز محاذاة داخل الصفحة أي رمز محاذاة آخر. […] يمكن أن يحتوي المقطع على سمة داخل الصفحة، مما يعني أنه يجب أن يكون موجودًا داخل صفحة بحجم 256 بايت، ويمكن أن يحتوي على سمة كلمة، مما يعني أنه يجب أن يكون موجودًا على بايت ذي رقم زوجي. […]
روابط خارجية
- مقال من IBM Developer حول محاذاة البيانات
- مقال حول مواءمة البيانات والأداء
- مقال من مايكروسوفت ليرن حول محاذاة البيانات
- مقال حول مواءمة البيانات وقابلية نقل البيانات
- محاذاة وترتيب البايتات
- محاذاة المكدس في اصطلاحات الاستدعاء 64 بت على موقع Wayback Machine (تمت أرشفته في 29-12-2018) – يناقش محاذاة المكدس لاصطلاحات الاستدعاء x86-64
- فن التعبئة الهيكلية المفقود بقلم إريك س. ريموند
- بناء المترجم
- أنواع البيانات المركبة
