أنظف تركيب المؤشر الحسابي للتلاعب مع إزاحة البايت

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

سؤال

في الأسطر التالية من التعليمات البرمجية، ولست بحاجة لضبط pm المؤشر بواسطة إزاحة بالبايت في واحدة من حقولها. هل هناك أسهل طريقة أفضل / للقيام بذلك، من الصب باستمرار ذهابا وإيابا من char * وPartitionMap * بحيث الحساب المؤشر لا يزال يعمل بها؟

PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
    pm = (PartitionMap *)(((char *)pm) + pm->partitionMapLength);
}
return pm;

لتلك التي لا يمكن جروك من التعليمات البرمجية، انها حلقات من خلال واصفات طول متغير في منطقة عازلة التي ترث من PartitionMap.

وأيضا لأولئك المعنيين، partitionMapLength دوما بإرجاع أطوال التي يدعمها النظام هذا يعمل على. البيانات أنا على عبور متفق عليها الى حد UDF المواصفات.

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

المحلول

وأنا غالبا ما تستخدم هذه القوالب لذلك:

    template<typename T>
    T *add_pointer(T *p, unsigned int n) {
            return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + n);
    }

    template<typename T>
    const T *add_pointer(const T *p, unsigned int n) {
            return reinterpret_cast<const T *>(reinterpret_cast<const char *>(p) + n);
    }

وأنها تحافظ على نوع، ولكن إضافة بايت واحد لهم، على سبيل المثال:

T *x = add_pointer(x, 1); // increments x by one byte, regardless of the type of x

نصائح أخرى

والصب هو السبيل الوحيد، سواء كان ذلك لشار * أو intptr_t أو غيرها من بعض هذا النوع، ومن ثم إلى نوع النهائي.

ويمكنك بالطبع تبقي فقط متغيرين حول: أ char * للدخول إلى عازلة وPartitionMap * للوصول إليه. يجعل من قليلا أكثر وضوحا ما يجري.

for (char *ptr = ??, pm = (PartitionMap *)ptr ; index > 0 ; --index)
{
    ptr += pm->partitionMapLength;
    pm = (PartitionMap *)ptr;
}
return pm;

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

واحدة من عدد قليل من أبنية (حتى لو كان على وشك الاكثر شهرة) سيتيح لك ان تفلت من العقاب هو العمارة إلى x86. ومع ذلك، حتى لو كنت تكتب عن ويندوز، فأنت تريد أن تأخذ هذه المشكلة بعين الاعتبار - Win64 لا فرض متطلبات التوافق

وهكذا حتى الوصول إلى أعضاء partitionMapLength خلال المؤشر قد تعطل البرنامج.

وكنت قد تكون قادرة على العمل بسهولة تغلب على هذه المشكلة باستخدام ملحق مترجم مثل __unaligned على نظام التشغيل Windows:

PartitionMap __unaliged *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
    pm = (PartitionMap __unaligned *)(((char *)pm) + pm->partitionMapLength);
}
return pm;

وأو يمكنك نسخ البيانات يحتمل الصغيرة المحايدة في البنية محاذاة بشكل صحيح:

PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));

char* p = reinterpret_cast<char*>( pm);

ParititionMap tmpMap;
for ( ; index > 0 ; --index)
{

    p += pm->partitionMapLength;

    memcpy( &tmpMap, p, sizeof( newMap));
    pm = &tmpMap;
}

// you may need a more spohisticated copy to return something useful
size_t siz = pm->partitionMapLength;
pm = reinterpret_cast<PartitionMap*>( malloc( siz));
if (pm) {
    memcpy( pm, p, siz);
}
return pm;

والصب الذي ينبغي القيام به، ولكنه يجعل رمز غير قابل للقراءة تقريبا. من أجل سهولة القراءة، وعزلها في وظيفة static inline.

ما يبعث على الحيرة لي هو لماذا لديك "partitionMapLength" في بايت؟

ولن يكون أفضل إذا كان في الوحدات partitionMap "منذ كنت على أي حال يلقي ذلك؟

PartitionMap *pmBase(reinterpret_cast<PartitionMap *>(partitionMaps));
PartitionMap *pm;
...
pm = pmBase + index; // just guessing about your 'index' variable here

وكلا C و C ++ تسمح لك لتكرار خلال مجموعة عبر مؤشرات و++:

#include <iostream>

int[] arry = { 0, 1, 2, 3 };
int* ptr = arry;
while (*ptr != 3) {
    std::cout << *ptr << '\n';
    ++ptr;
}

لهذا العمل، ويعرف مشيرا إلى مؤشرات لاتخاذ عنوان الذاكرة المخزنة في مؤشر وثم إضافة sizeof مهما كان نوع غير الأوقات التي تضاف القيمة. على سبيل المثال، في مثالنا ++ptr يضيف 1 * sizeof(int) إلى عنوان الذاكرة المخزنة في ptr.

إذا كان لديك مؤشر إلى نوع، وتريد أن تقدم عدد معين من وحدات البايت من تلك البقعة، والطريقة الوحيدة للقيام بذلك هي للادلاء إلى char* (لأنه يتم تعريف sizeof(char) لتكون واحدة).

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