في C: كيفية ضبط مؤشر على عضو هيكل وهو صفيف؟
-
21-09-2019 - |
سؤال
كيف يمكنني كتابة الكود الخاص بي إلى مثال فهرس صفيف محدد لمجموعة يحدث ليكون عضوًا في هيكل؟ الرمز التالي يعطيني مشاكل.
// main.c
void clean_buffers(void); // prototype
struct DEV_STATUS {
unsigned char ADDR;
unsigned char DEV_HAS_DATA;
unsigned char ETH_HAS_DATA;
unsigned char DATA[20];
};
struct DEV_STATUS g_cmdQueue[60] = {0};
void main(void) {
clean_buffers();
while (1) {
;// MCU tasks
}
}
void clean_buffers(void) {
unsigned char theCount = 0;
byte queIdx;
for (queIdx = 0; queIdx < 59; queIdx++) {
struct DEV_STATUS *p_struct;
unsigned char *p_data;
p_struct = &g_cmdQueue[queIdx];
p_data = &p_struct->DATA;
p_struct->ADDR = 0;
p_struct->DEV_HAS_DATA = 0;
p_struct->ETH_HAS_DATA = 0;
theCount = 0;
while(*(p_data+theCount) != 0) {
*(p_data+(theCount++)) = 0;
}
}
} // EOF main.c
أحصل على خطأ في المترجم "هيكل/عضو الاتحاد المتوقع" على السطر التالي:
p_data = &p_struct->DATA;
كيف يجب أن أكتب مؤشرًا إذا أردت الوصول ، على سبيل المثال ، القيمة المحددة لبيانات عضو الهيكل [3]؟ أنا في حيرة من أمري ، اعتقدت أن البيانات p_data = & p_struct-> ؛ تم تعريفه ، يجب أن أكون قادرًا على الحصول عليه باستخدام *(PDATA+3) ولكن أعتقد أنني أفتقد شيئًا ما.
المحلول
هل أنت متأكد من أنك تقوم بتجميع نفس الرمز الذي نشرته هنا؟
إذا كان المترجم الخاص بك يشكو في هذا الخط
p_data = &p_struct->DATA;
من خلال رسالة "متوقعة للبنية/الاتحاد" ، من المحتمل أن يتم كسر المترجم الخاص بك.
لاحظ أن &p_struct->DATA
هو تعبير صحيح تمامًا في C. لا يوجد أي مشاكل على الإطلاق في هذا التعبير في حد ذاته.
المشكلة هنا هي أن هذا ليس ما تحتاجه في قضيتك. &p_struct->DATA
إرجاع مؤشر إلى صفيف "بيانات" بأكمله ، أي مؤشر من النوع unsigned char (*)[20]
. أنت تحاول تعيين هذه القيمة إلى مؤشر من النوع unsigned char *
. هذا غير قانوني في C ، لأن الأنواع مختلفة تمامًا ، ولكن تقليديًا استجابوا للمترجمين C بتحذير "عدم تطابق النوع" وأجرى تحويلًا ضمنيًا (والذي يعني ، راجع للشغل ، أن الكود الأصلي ، وإن كان "قذرًا" لا تزال تعمل على النحو المقصود).
حتى إذا قرر بعض البرمجيات الإبلاغ عن هذا عدم التطابق كخطأ (وهو أمر جيد) ، فلا يزال يتعين عليه الشكوى من أي مشاكل من نوع "هيكل/الاتحاد عضو". لا توجد مثل هذه المشاكل هنا.
ملاحظة كما قال آخرون بالفعل ، ما تحتاجه حقًا هو p_data = &p_struct->DATA[0]
, ، لكن هذا لا يزال لا يفسر سلوك المترجم الغريب. هل يمكن أن يكون "البيانات" هو ماكرو محدد في مكان ما قبل تعريف "Clean_Buffers"؟
تمت إضافة 10/19/2009: Nate ، في الكود الخاص بك يمكنك الوصول إلى صفيفك باستخدام فهرس theCount
. نظرًا لأنك تستخدم وصول الفهرس على أي حال ، فلا يوجد سبب لإنشاء المؤشر الذي تحاول إنشاؤه. سيعمل الرمز بشكل جيد تمامًا دون أي مؤشر إضافي ، فقط DATA
الحقل مباشرة
theCount = 0;
while (p_struct->DATA[theCount] != 0) {
p_struct->DATA[theCount++] = 0;
(ربما كنت أستخدم ملف for
دورة هنا).
إذا كنت تصر حقًا على إنشاء هذا المؤشر وما زالت تستخدم وصول الفهرس ، فيجب أن يبدو الرمز مثل ما يلي (اقترح الآخرون بالفعل أكثر من مرة)
p_data = p_struct->DATA; /* or &p_struct->DATA[0] */
...
theCount = 0;
while (p_data[theCount] != 0) {
p_data[theCount++] = 0;
علاوة على ذلك ، يمكنك اختيار متغير أكثر "غريبة" :)
unsigned char (*p_data)[20]; /* <- note: declared differently */
...
p_data = &p_struct->DATA; /* <- note: your original version */
...
theCount = 0;
while ((*p_data)[theCount] != 0) {
(*p_data)[theCount++] = 0;
ومع ذلك ، العودة إلى أ unsigned char *p_data
الإصدار ، نظرًا لأنك تقوم بإنشاء هذا المؤشر ، فقد يكون من المنطقي استخدام تقنية "مؤشر منزلق" بدلاً من استخدام الوصول إلى الفهرس
unsigned char *p_data;
...
p_data = p_struct->DATA; /* or &p_struct->DATA[0] */
...
while (*p_data != 0) {
*p_data++ = 0;
كما هو الحال دائمًا ، إنها مسألة تفضيل شخصي. بالطبع ، لن يعمل أي شيء من هذا حتى تتخلص من هذا التداخل من الماكرو.
نصائح أخرى
تفقد & في p_data = &p_struct->DATA;
p_struct هو بالفعل مؤشر. بعد ذلك ، استخدم p_data [] للوصول إلى صفيفك.
ما يجب أن تكتبه هو أحد شيئين:
p_data = p_struct->DATA; // DATA is the address of the first element.
أو
p_data = &p_struct->DATA[0]; // taking the address of the first element.
ما عليك سوى إزالة & في البداية ، مثل هذا:
p_data = p_struct->DATA;
هذا هو sintax خاص للمصفوفات (تذكر أنه يتم تمريره دائمًا كمرجع) وهو ما يعادل:
p_data = &p_struct->DATA[0];
ونعم ، يمكنك الآن استخدام *(PDATA+3)
أتمنى أن يساعد ذلك.
أُووبس! شكرا لك أندريه
struct dev_status *p_struct ؛ char غير موقعة *p_data ؛ p_struct = & g_cmdqueue [queidx] ؛ p_data = & p_struct-> data ؛
p_struct
هو مؤشر ل struct DEV_STATUS
.
&p_struct
هو عنوان المؤشر إلى struct DEV_STATUS
(أو مؤشر إلى مؤشر إلى struct DEV_STATUS
).
ربما تريد تغيير هذا الخط إلى
p_data = p_struct->DATA;
أوه ... الخاص بك clean_buffers()
الوظيفة لا "تنظيف" العنصر g_cmdQueue[59]
.
ولأنه كائن عالمي ، المصفوفة g_cmdQueue
تتم تهيئته إلى جميع الأصفار حتى قبل البيان الأول لـ main()
exceepts.