C struck الاستيلاء على البيانات عن طريق الإزاحة

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

  •  05-07-2019
  •  | 
  •  

سؤال

دعنا نقول لدي هذا الهيكل:

typedef struct nKey {
    int num;
    widget* widget;
} NUMBER_KEY;

ووظيفة:

void dialKey(widget* widget) {
    // Need to print 'num' of the struct that this widget resides in
}

كيف يمكنني إنجاز هذا؟ حاولت شيئًا مثل:

    printf("%d", * (int *) widget - sizeof(int)); // Failure.org

تحرير: من الآمن افتراض أن القطعة التي يتم تمريرها هي في الواقع عضو في هيكل رقم _key

تحرير: البحث عن حل للمشكلة وليس طريقة أخرى.

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

المحلول

بالنظر إلى مجرد widgit* وليس widgit ** يتم تمريره إلى DialKey ، لا توجد طريقة للقيام بما تريد (قيمة widgit* ليس لها علاقة بـ number_key struct). على افتراض أنك تعني حقًا شيئًا مثل:

void dialKey(widget** ppWidget) 
{    
    // Need to print 'num' of the struct that this widget resides in
}

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

#define CONTAINING_RECORD(address, type, field) ((type *)( \
                               (PCHAR)(address) - \
                               (ULONG_PTR)(&((type *)0)->field)))

يمكنك استخدام هذا مثل ذلك:

NUMBER_KEY* pNumberKey = CONTAINING_RECORD( *ppWidgit, NUMBER_KEY, widgit);

printf( "%d", pNumberKey->num);

نصائح أخرى

كما يشرح مايكل في إجابته ، لا يمكنك القيام بذلك مع قيود معينة لأنه لا توجد طريقة "للتراجع" الرسم البياني للمؤشر. لجعل الأمور أكثر وضوحًا ، اسمحوا لي أن أرسم مخططًا للكائنات (من حيث C ، وليس بالمعنى) المعني:

+- NUMBER_KEY --+
|  ...          | points to      
| widget field -+-----------+
|  ...          |           |
+---------------+           |   + widget +
                            +-->|  ...   |
                                |  ...   |
                            +-->|  ...   |
                            |   +--------+
                  points to |
[widget argument]-----------+

لاحظ الأسهم. إنها في اتجاه واحد - يمكنك "المشي" من مؤشر إلى قيمة مدببة ، لكن لا يمكنك "المشي" مرة أخرى. حتى تتمكن من الاحترام widget حجة وظيفتك للوصول إلى widget كائن ، ولكن بمجرد وجوده ، لا توجد طريقة لإخبار من يشير إليه - بما في ذلك أي حالات NUMBER_KEY هياكل. فكر في الأمر: ماذا لو كان لديك عشرات المؤشرات الأخرى widget, ، بعضهم من مختلف NUMBER_KEY أشياء؟ كيف يمكن أن تتبع ذلك دون الاحتفاظ بقائمة بجميع المؤشرات في الداخل widget هدف؟ إذا كنت بحاجة فعلاً إلى هذا ، فهذا ما عليك فعله - قم بعمله widget أشر إلى امتلاكها NUMBER_KEY.

يتم تعريف تخطيط ذاكرة الهيكل بواسطة برنامج التحويل البرمجي الخاص بك ، وسيعمل الكود الخاص بك فقط إذا كان لديك حشوة بايت 0 بين الأعضاء الهيكلية. عادةً ما لا ينصح بذلك حشوة بايت ب/ج 0 سيكون تراكب البنية عبر أحجام القراءة القياسية لمعظم المعالجات.

بعض وحدات الماكرو المفيدة لمشكلتك:

#define GET_FIELD_OFFSET(type, field)    ((LONG)&(((type *)0)->field))
#define GET_FIELD_SIZE(type, field)      (sizeof(((type *)0)->field))

مثال:

NUMBER_KEY key;
key.num = 55;
int nOffSetWidget = GET_FIELD_OFFSET( NUMBER_KEY, widget);
int *pKeyNumAddress = (int *) &(key.widget) - nOffSetWidget );

printf("%d", * pKeyNumAddress );    // Should print '55'

C المعيار المعياري offsetof() الماكرو (محدد في stddef.h رأس) ، وهو مفيد في قضيتك.

#include <stddef.h>

void DialKey(widget** foo) {
    printf("%d", *((char *)foo - offsetof(struct nKey, widget)));
}

لاحظ أنه يجب عليك تمرير تبوك من حقل الهيكل ، وليس قيمة!

الحل الأكثر أمانًا هو الحفاظ على مؤشر بنية nkey ذات الصلة في عنصر واجهة مستخدم

 printf("%d", widget->myKey->num);

جميع الطرق الأخرى غير آمنة

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