هل تتحرك القيم من نوع واحد مع نوع آخر تنتهك التعرج صارم؟

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

  •  20-09-2019
  •  | 
  •  

سؤال

هل تنتهك قواعد التعرجات مشددة لنقل العناصر من أي نوع حول استخدام uint32_t، ثم قراءتها مرة أخرى؟ إذا كان الأمر كذلك، فهل تنتهك أيضا قواعد صارمة لالتعرج memcpy من مجموعة من uint32_ts إلى مجموعة من أي نوع، ثم قراءة العناصر مرة أخرى؟

ونموذج التعليمات البرمجية التالية توضح كلتا الحالتين:

#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main(void) {
    const char *strings[5] = {
        "zero", "one", "two", "three", "four"
    };
    uint32_t buffer[5];
    int i;

    assert(sizeof(const char*) == sizeof(uint32_t));

    memcpy(buffer, strings, sizeof(buffer));

    //twiddle with the buffer a bit
    buffer[0] = buffer[3];
    buffer[2] = buffer[4];
    buffer[3] = buffer[1];

    //Does this violate strict aliasing?
    const char **buffer_cc = (const char**)buffer;
    printf("Test 1:\n");
    for (i=0; i<5; i++)
        printf("\t%s ", buffer_cc[i]);
    printf("\n");

    //How about this?
    memcpy(strings, buffer, sizeof(strings));
    printf("Test 2:\n");
    for (i=0; i<5; i++)
        printf("\t%s ", strings[i]);
    printf("\n");

    return 0;
}

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

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

المحلول

الحلقة الأولى <م> لا تنتهك تقنيا التعرج صارم - ويصل الأجسام uint32_t من خلال lvalue من نوع char *. فمن الصعب أن نرى كيف يمكن لأي محسن أن يسبب لك مشكلة في هذه الحالة تحديدا، وإن كان. إذا كنت تغييره قليلا حتى كنت تفعل شيئا مثل:

printf("\t%s ", buffer_cc[0]);
buffer[0] = buffer[3];
printf("\t%s ", buffer_cc[0]);

أنت <م> قد نرى نفس سلسلة طبعت مرتين - منذ محسن سيكون من حقها لتحميل buffer_cc[0] فقط إلى تسجيل مرة واحدة، لأن الخط الثاني يتم تعديل فقط كائن من نوع uint32_t

الحلقة الثانية، التي memcpys اعادتهم، على ما يرام.

نصائح أخرى

وbuffer_cc[0] وstrings[3] (على سبيل المثال) هي المؤشرات التي تشير إلى نفس الموقع الذاكرة، ولكن هي من نفس النوع، وبالتالي لا تنتهك التعرج صارمة. buffer[0] ليس المؤشر، وبالتالي لا تنتهك التعرج صارمة. تنشأ تحسينات التعرج عندما dereferencing المؤشرات، ولذا فإنني لن نتوقع أن تسبب مشاكل.

وكما أشير إليه في رمز والفقرة الأخيرة في سؤالك، والمشكلة الحقيقية في نموذج التعليمات البرمجية تنشأ عندما مؤشرات وuint32_t ذات أحجام مختلفة.

وبالإضافة إلى ذلك، يمكنك دائما اسم مستعار لchar* للإشارة إلى نوع آخر من دون انتهاك التعرج صارم، ولكن ليس العكس.

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