c++ - array - sizeof php




لماذا لا يكون sizeof لبنية مساوية لمجموع حجم كل عضو؟ (8)

لماذا يقوم مشغل 'sizeof' بإرجاع حجم أكبر للهيكل من إجمالي أحجام أعضاء الهيكل؟


أنظر أيضا:

لـ Microsoft Visual C:

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx

ومطابقة مطالبة مجلس التعاون الخليجي مع شركة مايكروسوفت.

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

بالإضافة إلى الإجابات السابقة ، يرجى ملاحظة أنه بغض النظر عن العبوة ، لا يوجد أي أعضاء-طلب-ضمان في C ++ . قد compilers (وبالتأكيد فعل) إضافة أعضاء الجدول الظاهري وأعضاء البنية الأساسية إلى البنية. حتى أن وجود جدول افتراضي لا يضمنه المعيار (لم يتم تحديد تطبيق الآلية الافتراضية) ، وبالتالي يمكن للمرء أن يستنتج أن هذا الضمان مستحيل.

أنا متأكد من أن ترتيب الأعضاء مضمون في C ، ولكن لن أعتمد عليه ، عند كتابة برنامج عبر منصة أو برنامج مترجم.


إذا كنت ترغب في أن يكون للهيكل حجم معين مع GCC ، على سبيل المثال ، استخدم __attribute__((packed)) .

على Windows ، يمكنك ضبط المحاذاة إلى بايت واحد عند استخدام مجيب cl.exe مع خيار / Zp .

عادة ما يكون من الأسهل لوحدة المعالجة المركزية الوصول إلى البيانات التي هي مضاعفات 4 (أو 8) ، اعتمادًا على النظام الأساسي وكذلك على المحول البرمجي.

لذلك هي مسألة المواءمة في الأساس.

يجب أن يكون لديك أسباب وجيهة لتغييرها.


بالإضافة إلى الإجابات الأخرى ، يمكن للهيكل (ولكن عادة لا) أن يكون له وظائف ظاهرية ، وفي هذه الحالة فإن حجم البنية سيشمل أيضًا مساحة vtbl.


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

struct pixel {
    unsigned char red;   // 0
    unsigned char green; // 1
    unsigned int alpha;  // 4 (gotta skip to an aligned offset)
    unsigned char blue;  // 8 (then skip 9 10 11)
};

// next offset: 12

كانت بنية x86 دائمًا قادرة على جلب العناوين غير الصحيحة. ومع ذلك ، فإنه أبطأ وعندما تتداخل المحاذاة غير الصحيحة بين سطرين مخملين مختلفين ، فإنه يقوم بإفشاء خطين مؤقتين عندما يؤدي الوصول إلى المحاذاة إلى إبطال واحدة فقط.

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

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

TL ؛ DR: المحاذاة أمر مهم.


هذا بسبب إضافة الحشو لتلبية قيود المحاذاة. تؤثر محاذاة هيكل البيانات على أداء البرامج وصحتها:

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

إليك مثال على ذلك باستخدام الإعدادات النموذجية لمعالج x86 (جميع أوضاع 32 و 64 بت المستخدمة):

struct X
{
    short s; /* 2 bytes */
             /* 2 padding bytes */
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 3 padding bytes */
};

struct Y
{
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
    short s; /* 2 bytes */
};

struct Z
{
    int   i; /* 4 bytes */
    short s; /* 2 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */

يمكن للمرء تقليل حجم الهياكل عن طريق فرز الأعضاء عن طريق المحاذاة (الفرز حسب الحجم يكفي لذلك في الأنواع الأساسية) (مثل الهيكل Z في المثال أعلاه).

ملاحظة هامة: كلا من معايير C و C ++ حالة محاذاة بنية يتم تعريف التطبيق. لذلك قد يختار كل مترجم لمحاذاة البيانات بشكل مختلف ، مما يؤدي إلى تنسيقات بيانات مختلفة وغير متوافقة. لهذا السبب ، عند التعامل مع المكتبات التي سيتم استخدامها من قبل مختلف المجمعين ، من المهم فهم كيفية محاذاة المجمعين للبيانات. تحتوي بعض برامج التحويل البرمجي على إعدادات سطر الأوامر و / أو عبارات #pragma خاصة لتغيير إعدادات محاذاة البنية.


ويمكنه القيام بذلك إذا قمت بتعيين ضبط البنية بشكل ضمني أو صريح. سيكون البادئة التي تتم محاذاتها 4 دومًا مضاعفات 4 بايت حتى إذا كان حجم أعضائها شيئًا لا يتعدى 4 بايت.

قد يتم أيضًا تجميع مكتبة ضمن الإصدار x86 مع وحدات بايت 32 بت وقد تكون مقارنة مكوناتها على عملية 64 بت قد تمنحك نتيجة مختلفة إذا كنت تقوم بذلك يدويًا.


C99 N1256 مسودة قياسية

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.5.3.4 مشغل الحجم :

3 عند تطبيقه على مُعامل به بنية أو نوع اتحاد ، فإن النتيجة هي العدد الإجمالي للبايتات في مثل هذا الكائن ، بما في ذلك الحشوة الداخلية والخارجية.

6.7.2.1 محددات الهيكل والنقابة :

13 ... قد يكون هناك مساحة غير مسماة داخل كائن بنية ، ولكن ليس في بدايتها.

و:

15 قد تكون هناك مساحة غير مسماة في نهاية الهيكل أو الاتحاد.

ميزة عضو المصفوفة المرن C99 ( struct S {int is[];}; ) قد تؤثر أيضًا على الحشو:

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

يكرر قضايا القابلية للنقل في الملحق J :

فيما يلي غير محدد: ...

  • قيمة وحدات البايت الخاصة بالحشو عند تخزين القيم في الهياكل أو النقابات (6.2.6.1)

C ++ 11 N3337 مسودة قياسية

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

5.3.3 الحجم :

2 عند تطبيقه على فئة ، تكون النتيجة عدد وحدات البايت في كائن من هذه الفئة بما في ذلك أي حشوة مطلوبة لوضع كائنات من هذا النوع في صفيف.

9.2 أعضاء الصف :

يشير مؤشر إلى كائن هيكلي تخطيطي قياسي ، تم تحويله بشكل مناسب باستخدام reinterpret_cast ، إلى عضوه الأولي (أو إذا كان هذا العضو عبارة عن حقل بت ، ثم إلى الوحدة التي توجد فيه) والعكس صحيح. [ملاحظة: قد يكون هناك بالتالي مساحة غير مسماة داخل كائن هيكلي تخطيطي قياسي ، ولكن ليس في بدايته ، حسب الضرورة لتحقيق المواءمة المناسبة. - ملاحظة النهاية

أنا أعرف ما يكفي من C ++ لفهم الملاحظة :-)


ج لغة يترك مترجم بعض الحرية حول موقع العناصر الهيكلية في الذاكرة:

  • قد تظهر ثقوب الذاكرة بين أي مكونين ، وبعد آخر مكون. كان ذلك بسبب حقيقة أن أنواع معينة من الكائنات على الكمبيوتر الهدف قد تكون محدودة بسبب حدود العنونة
  • حجم "ثقوب الذاكرة" المضمنة في نتيجة مشغل sizeof. لا يتضمن sizeof فقط حجم الصفيف المرن ، والذي يتوفر في C / C ++
  • بعض تطبيقات اللغة تسمح لك بالتحكم في تخطيط الذاكرة للهياكل من خلال خيارات pragma و compiler

توفر لغة C بعض الضمانات لمبرمج عناصر التصميم في البنية:

  • compilers مطلوبة لتعيين تسلسل من المكونات زيادة عناوين الذاكرة
  • يتطابق عنوان المكون الأول مع عنوان بداية البنية
  • قد يتم تضمين حقول بتات غير مسماة في البنية إلى محاذاة العنوان المطلوبة للعناصر المجاورة

المشاكل المتعلقة بمحاذاة العناصر:

  • تقوم أجهزة الكمبيوتر المختلفة بضبط حواف الكائنات بطرق مختلفة
  • قيود مختلفة على عرض حقل البت
  • تختلف أجهزة الكمبيوتر عن كيفية تخزين وحدات البايت في كلمة (Intel 80x86 و Motorola 68000)

كيف يعمل المحاذاة:

  • يتم حساب الحجم الذي تشغله البنية على أنه حجم العنصر الأحادي المحاذاة لمجموعة من هذه الهياكل. يجب أن ينتهي الهيكل بحيث لا ينتهك العنصر الأول في الهيكل التالي التالي متطلبات المواءمة

معلومات أكثر تفصيلاً متوفرة هنا: "Samuel P.Harbison، Guy L.Steele CA Reference، (5.6.2 - 5.6.7)"





c++-faq