سؤال

فيما يلي وظيفة أكتبها على جهاز Linux 64 بت.

void myfunc(unsigned char* arr) //array of 8 bytes is passed by reference
{
   unsigned long a = 0; //8 bytes
   unsigned char* LL = (unsigned char*) &a;

   LL[0] = arr[6];
   LL[1] = arr[3];
   LL[2] = arr[1];
   LL[3] = arr[7];
   LL[4] = arr[5];
   LL[5] = arr[4];
   LL[6] = arr[0];
   LL[7] = arr[2];
}

الآن أسئلتي هي:

  1. هل سيتم تخزين المتغير "A" في سجل بحيث لا يتم الوصول إليه مرارًا وتكرارًا من ذاكرة الوصول العشوائي أو Chache؟
  2. العمل على بنية 64 بت ، هل يجب أن أفترض أنه سيتم تخزين صفيف "ARR" في السجل حيث يتم تخزين معلمات الوظائف في سجل في قوس 64 بت؟
  3. ما مدى كفاءة صب نوع المؤشر؟ أظن أنه يجب أن يكون غير فعال على الإطلاق؟

أي مساعدة سيتم عرضها.

يعتبر

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

المحلول

  1. a لا يمكن تخزينها في السجل ، حيث أخذت عنوانها. (يشير فالدو بشكل صحيح إلى أن برنامج التحويل البرمجي الذكي حقًا استطاع قم بتحسين الوصول إلى Array Access في عمليات بت ومغادرة a في السجل ، لكنني لم أر أبدًا برنامجًا مترجمًا يفعل ذلك ، ولست متأكدًا من أنه سينتهي بشكل أسرع).
  2. arr (المؤشر نفسه) يتم تخزينه في السجل (%edi, ، على AMD64). ال محتويات الصفيف في الذاكرة.
  3. نوع المؤشر الصب بنفسها غالبًا ما لا يولد أي رمز على الإطلاق. ومع ذلك ، يمكن أن يؤدي القيام بأشياء سخيفة باستخدام Type Type إلى رمز غير فعال للغاية ، أو حتى إلى رمز لا يتم تعريف سلوكه.

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

بالمناسبة ، يجب أن تجعل نوع الإرجاع لوظيفة المثال الخاص بك unsigned long و ضع return a; في النهاية؛ ثم يمكنك استخدام gcc -O2 -S وانظر بالضبط ما تحصل عليه من التجميع. بدون تغيير للعودة a, ، ستعمل GCC على تحسين الجسم الكامل للوظيفة ، لأنه ليس له آثار جانبية مرئية خارجيًا.

نصائح أخرى

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

ستجعل عمليات الصفيف من الصعب على المترجم استخدام سجلات لهذا ، لأنه لا توجد عادةً تعليمات تقوم بأشياء مثل "تحميل 8 بت من البايت الثالث من التسجيل A". (مترجم تحسين استطاع اكتشف أنه من الممكن القيام بذلك مع التحولات/الأقنعة ، لكنني لست متأكدًا من مدى احتمال ذلك).

  1. السؤال حول ما إذا كان المتغير a سيتم تخزينها في السجل مسألة تحسين. لأنه لا يوجد volatile المعدل IMHO المترجم الذكي سيقوم بذلك.

  2. إنها مسألة اتفاقية الاتصال. إذا تم نقل معلمة مؤشر واحد بالاتفاقية في السجل - فسيكون ذلك arr.

  3. إن نوع المؤشر ليس عملية تفسرها وحدة المعالجة المركزية. لا يوجد رمز تم إنشاؤه لذلك. إنها مجرد معلومات للمترجم حول ماذا تقصد.

(في الواقع في بعض الأحيان ، ينتج الصب رمزًا إضافيًا ، ولكن هذا يرتبط بالميراث المتعدد وتعدد الأشكال)

يعتمد على مستوى التحسين الخاص بك. يمكنك فحص التجميع للإجابة على أسئلتك. مع GCC ، استخدم علامة "-S".

gcc -S -O0 -o /tmp/xx-O0.s /tmp/xx.c
gcc -S -O3 -o /tmp/xx-O3.s /tmp/xx.c

التجميع المولد تماما مختلف. (تأكد من صنع return a; التغيير اقترحه زاك.)

أنظر أيضا هذه الرسالة للحصول على تلميحات حول كيفية إنشاء قائمة C/التجميع مختلطة (والتي تصبح بسرعة عديمة الفائدة مع التحسين).

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