هل يتغير الصب إلى نوع مختلف كثيرًا؟


مرحبًا !

لدي سؤال سريع، كنت أتساءل ما هي التغييرات في نوع طاقم التمثيل. على سبيل المثال :

#include <stdio.h>
#include <stdlib.h>

int main()
{
int *x;
char *y;
float *z;

x = (int*)y;
y = (char*)z;

return 0;
}

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

على سبيل المثال، إذا كان المؤشر “x” عبارة عن int ويشير إلى حرف، فإن الحجم الحسابي x+1 أو x+i يعتمد على نوع “x” وليس نوع “y”.

فلماذا نحتاج إلى تغيير طاقم المتغيرات الأخرى؟

أساسًا :

#include <stdio.h>
#include <stdlib.h>

int main()
{
int *x;
char *y;

x = (int*)y;
x = (char*)y;

return 0;
}

لا ينبغي أن يغير أي شيء.

أدرك أن خلط الأنواع ليس فكرة جيدة، لكنني كنت مختلطًا بعض الشيء مع اختيار النوع لأكون صادقًا.

ملاحظة.

لقد وجدت بعض الأمثلة على كيفية تغيير نوع الممثلين:

يقتبس:

*(int *)((char *)ptr + 2*sizeof(int))

لم أكن أعرف كثيرًا ما يحدث هنا ولماذا تم تغيير نوع ptr مرتين. هذا شيء يتعلق بحسابات المؤشر لكنني تخيلت أنه إذا كان لدي ptr + 1 فهو (ptr+1*sizeof(int))، وهنا لدي (char*) وآخر (int*) لذلك لدي (ptr) +1*sizeof(int)) مرات sizeof(char) ثم مرات sizeof(int) ؟؟؟؟ غريب.

ما حاولت:

حاولت أن أفكر في الغالب في سبب حدوث ذلك عندما يأخذ المؤشر العنوان فقط، فلماذا يتغير النوع.

الحل 3

لا يقوم طاقم الممثلين بإجراء أي تغييرات على البيانات. يمكن اعتبارها إشارة إلى المترجم “نعم، أعلم أن x وy نوعان مختلفان، لكن قم بالمهمة على أي حال!”. يقوم المترجم بعد ذلك بترتيب نسخة بت من x إلى y. إذا حصلت على تغيير في القيمة، فسيكون ذلك بسبب الاختلاف في حجم المصدر والهدف على سبيل المثال

ج
int i = 256;  /* 0x100 */
char c = i;  /*  c will be assigned 0x00 ie. last byte of i */

أنت بحاجة إلى توخي الحذر عند التنقل بين مؤشرات من أنواع مختلفة. بشكل عام، لا يحتوي مؤشر char (مؤشر إلى بايت واحد) على متطلبات محاذاة، ولكن الأنواع الأخرى، مثل int، قد تتطلب محاذاته على حد 4 بايت (أو 2 أو 8 أو 16، وما إلى ذلك اعتمادًا على نوع). في هذه الحالة، قد تحصل على خطأ عند محاولة إلغاء الإشارة إلى المؤشر. على سبيل المثال

ج
char str[5] = { 0x00, 0x00, 0x00, 0x00, 0x0 };  /* a 5 byte string, all zeros */
int *i = (int *)&(str[0]);
printf("*i = %d\n", *i);  
i = (int*)(&str[1]);
printf("*i = %d\n", *i);

بالنظر إلى القيود المذكورة أعلاه، ستؤدي إحدى عبارات printf إلى حدوث خطأ seg، حيث تتم محاذاة أحد مؤشرات int بشكل خاطئ وفقًا لمتطلبات وحدة المعالجة المركزية (CPU). لذلك عليك أن تكون حذرًا فيما تفعله عند إرسال المؤشرات من نوع إلى آخر. لاحظ أن malloc() والمكالمات ذات الصلة مضمونة لإرجاع مؤشر تمت محاذاته بشكل صحيح لأي نوع، لذلك لن تواجه أي مشاكل في القيام بذلك type *ptr = (type*)malloc(sizeof(*ptr) * 42)

الحل 1

إذا قمت بإجراء 1+ على المؤشر، فإنه ينقل المؤشر إلى العنوان التالي بعد الكتابة.
إذا قمت بإجراء +1 على المؤشر إلى 4 بايت، فسيرتفع العنوان بمقدار 4 بايت.
إذا قمت بإجراء 1+ على المؤشر إلى 8 بايت مزدوج، فسوف يرتفع بمقدار 8 بايت.

لفهم سبب وجود قالبين، عليك أن تنظر إلى الأقواس.
عادةً ما يتم التحويل إلى char لأنه يجعل أي مؤشر حسابي يستخدم “1” كحجم ليتم العد به.

لذا، يتم التعامل مع ptr باعتباره char* ثم إضافة ضعف حجم int (والذي سيكون 4 في نظام 32 أو 64 بت افتراضيًا). هذا يعني أنك تحاول قراءة int، وإزالة 8 بايت من ptr.
هناك طريقة أبسط بكثير لكتابة ذلك

*((int *)ptr + 2)

أو إذا كان ptr من النوع int*، فما عليك سوى القيام بذلك

*(ptr + 2)

الحل 2

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

ج
#include <stdio.h>
int main()
{
  float f = -0.25;
  printf("%04X", *(unsigned int *) &f);
}

النواتج

BE800000

هذا هو نمط البت من float، وفقا ل IEEE 754 معيار.

コメント

タイトルとURLをコピーしました