الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

كود غريب في عملية Cast

بدأه azzoz2 في 27 فبراير 2009 · 8 رد · 927 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله وبركاته

ممكن تفسير يا إخوان لمخرجات هذا الكود ؟؟؟؟

#include <iostream> 
		 using namespace std; 
		 int main() 
		 { 
		 double x, y; 
		 int *p; 
		 x = 123.23; 
		 p = (int *) &x; // use cast to assign double * to int * 
		 *p = 79; 
		 y = *p; 
		 cout<<"x is : "<<x<<endl; 
		 cout<<"*P is "<<*p<<endl; 
		 cout <<"y is "<<y<<endl; 
		 cout<<"the address of x "<<&x<<endl; 
		 cout<<"p point to "<<p<<endl;  
		 system("pause"); 
		 return 0; 
		 }

ممكن تفسير .... لماذا قيمة x لم تتغير ؟؟

مع أن :

*P is : 79

تم تعديل هذه المشاركة بواسطة azzoz2 في 27 فبراير 2009 في 13:28

#2

هذا النص منسوخ كما هو من كتاب

C The complete Reference 4th ed

اقتباس
Except for void *, all other pointer conversions must be performed by using an explicit cast.

However, the conversion of one type of pointer into another type may create undefined behavior.

For example, consider the following program that attempts to assign the value of x to y, through the

pointer p. This program compiles without error, but does not produce the desired result.



int main(void)

{

double x = 100.1, y;

int *p;

/* The next statement causes p (which is an integer pointer) to point to a double. */

p = (int *) &x;

/* The next statement does not operate as expected. */

y = *p; /* attempt to assign y the value x through p */

/* The following statement won't output 100.1. */

printf(''The (incorrect) value of x is: %f", y);

return 0;

}
#include <stdio.h>

Notice that an explicit cast is used when assigning the address of x (which is implicitly a double *

pointer) to p, which is an int * pointer. While this cast is correct, it does not cause the program to

act as intended (at least not in most environments). To understand the problem, assume 4-byte ints

and 8-byte doubles. Because p is declared as an integer pointer, only 4 bytes of information will be

transferred to y by this assignment statement,

y = *p;

not the 8 bytes that make up a double. Thus, even though p is a valid pointer, the fact that it points

to a double does not change the fact that operations on it expect int values. Thus, the use to which p

is put is invalid.

The preceding example reinforces the rule stated earlier: Pointer operations are performed relative to

the base type of the pointer. While it is technically permissible for a pointer to point to some other

type of object, the pointer will still ''think" that it is pointing to an object of its base type. Thus,

pointer operations are governed by the type of the pointer, not the type of the object being pointed

to.

لا يوضح الكتاب السبب بالضبط ولكنه يؤكد أن تصرف البرنامج في هذه الحالات ليس من الممكن توقعه... أرجو أن يكون هذا ذا فائدة

تم تعديل هذه المشاركة بواسطة أحمد مبارك الحيقي في 1 مارس 2009 في 18:17

#3

السلام عليكم ,,

لا أرى ما يثير العجب في الكود الذي وضعته :)

عندما تريد التحويل بين أنواع المتغيرات فإننا في ++C نستخدم الـ static_cast,

لكي نجعل كودك سليماً سنغير الكود ليصبح هكذا :

int main() 
{ 
	double x, y, z; 
	int p;

	x = 123.23; 
	p = static_cast<int>(x); // use cast to assign double * to int * 

	p = 79; 

	y = p;

	cout<<"x is : "<<x<<endl; 
	cout<<"*P is "<<p<<endl; 
	cout <<"y is "<<y<<endl; 
	cout<<"the address of x "<<&x<<endl; 
	cout<<"p point to "<<p<<endl;  

	system("pause"); 

	return 0; 
}

و لكن أنا لا أقول أن الكود الذي كتبته أنت خاطئ كل ما أقوله أنني أعتقد أنك تريد التحويل بين أنواع الأعداد, قمنا بعمليتي تحويل الأولى :

p = static_cast<int>(x);

static_cast تخبر المترجم أننا نريده أن يقوم بإنتاج الكود اللازم لتحويل double إلى int, هذا من خدمات ++C و C الجاهزة...

في التحويل الآخر :

y = p;

لم نستعمل static_cast لأن ++C تسمح بالـ implicit conversion ... نعلم أن y هي من النوع double و تستطيع حمل قيم int و أكثر من ذلك بكثير, لذلك لا خوف من عملية التحويل مهما كانت قيمة p :) و لهذا يمكن التحويل دون استخدام static_cast ...

أعود و أكرر أن كودك الأصلي ليس خاطئاً و لكنه hack :)

لا تلعب بالمؤشرات إن لم تكن تعرف ما تقوم به :)

ما مدى معرفتك بـ ++C, و سنتتبع كودك الأصلي سوية لنعرف مالذي يحصل بالضبط إذا أردت ;)

تحياتي, ,

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 1 مارس 2009 في 17:46

#4

السلام عليكم

عفواً أخي، لم أفهم قصدك جيداً.... الكلام هنا ليس عن التحويل بين أعداد ولكن بين مؤشر إلى double (وهو عنوان x : x&) و مؤشر إلى int وهو p. والمشكلة أنه عند تعيين

*p=79

المتوقع أن تصبح x = 79 أيضاً لأن p يحوي عنوان x.... هذا لا يحدث، والكتاب يذكر أن عملية تحويل أنواع المؤشر تولد نتائج غير متوقعة مثل هذه تماماً.... أظن أن هذا هو قصد الأخ السائل

والله أعلم

#5
اقتباس
المتوقع أن تصبح x = 79 أيضاً لأن p يحوي عنوان x.... هذا لا يحدث، والكتاب يذكر أن عملية تحويل أنواع المؤشر تولد نتائج غير متوقعة مثل هذه تماماً.... أظن أن هذا هو قصد الأخ السائل

جميل إذاً سأضع ما عندي على عجالة :)

اقتباس
والكتاب يذكر أن عملية تحويل أنواع المؤشر تولد نتائج غير متوقعة

هذا الكلام صحيح نسبياً, إذا قمت بتحديد نوع معالجك, فسأخبرك ماذا يحصل بالضبط,

عمليات التحويل الآمنة كـ static_cast لا تعتمد في عملها على المنصة التي يعمل عليها البرنامج, و لكن عندما تدخل المؤشرات في الموضوع فإن كل ما سبق يصبح هباء....

أولاً لنفترض أنك تعمل على منصة intel x86 و هذا ما أعتقده لأن حاسوبك شخصي كحاسوبي :)

في x86 فإن النوع int عبارة عن 32 bit .... و ربما تعرف هذا الكلام منذ أول يوم درست فيه ++C... و لكن ما هو النوع double ؟؟؟ إذا قلت بأنه نوع عددي حجمه 64 bit فكلامك خاطئ!

النوع double هو implementation للمواصفات القياسية المشهورة IEEE 754 standard,

هو ليس متغيراً بسيطاً كالأعداد الصحيحة integers, الحواسيب في الماضي لم يكن لها صيغة موحدة في التعامل مع الأعداد ذات الفاصلة العائمة, كل منصة كانت تختلف عن الأخرى....

هذه المقاييس وحدت التعامل مع الأعداد العائمة في الحواسيب... النوع double صحيح أنه مكون من 64 bits و لكنها ليست قطعة واحدة و إنما مقسمة إلى ثلاثة أجزاء, كما توضحها الصورة التالية :

post-89451-1235938811_thumb.png

باستخدام التمثيل العلمي للأعداد scientific notation فإنه بإمكاننا تخزين أعداد كبيرة جداً أو صغيرة جداً, و لكن لا تخلط هذا مع دقة العدد نفسه,

النوع double يستطيع حمل عدد "معين" من الخانات, ببساطة انظر للمثال التالي :

double x = 3.2654889255448965658589665589656588965588965655;
double y = 3.265e300;

في x سيتم اقتطاع 16 خانة فقط و الباقي لن يستطيع النوع double حفظه, أما في الحالة الثانية استطعنا أن نفصل حجم الرقم نفسه عن دقته :)

و بالتالي أصبح باستطاعة الحاسوب التعامل مع أعداد كبيرة جداً أو صغيراً جداً بدقة معقولة :)

اطلع على هذا الموضوع فقد شرحت فيه كيفية استخدام MAPM و هي مكتبة arbitrary precision numbers :

الأعداد العملاقة في ++C بمنتهى السهولة - شرح كامل

إذا أردت معرفة أكبر عدد و أصغر عدد يمكن للنوع double حملهما فعليك بكتابة التالي :

#include <limits>
.
.
std::cout << std::numeric_limits<double>::max() << std::endl << std::numeric_limits<double>::min();

الآن لماذا هذه المقدمة الطويلة ؟! :lol: أعرف أني أدخل في المواضيع عكس و لكن صبراً و الله المستعان :)

في كود صاحب الموضوع بالتحديد السطر التالي :

p = (int *) &x

و التي يمكن كتابتها في ++C بطريقة أخرى كالتالي :

p = reinterpret_cast<int*>(&x);

فإننا جعلنا مؤشر int يشير إلى double ؟؟!!

انظر إلى الصورة و ستعرف إلى أين أشار المؤشر :)

post-89451-1235938764_thumb.png

بالتالي فإنك إن غيرت أي شيء في قيمة المؤشر فستغير بعض الخانات و لكنك لن تغير قيمة العدد الكلية ...

و ذلك يظهر بوضوح في كودك :

*p = 79

في هذا السطر قمنا بالتلاعب بآخر 32 bit و بدلاً من أن يصبح x يساوي 79 أصبح يساوي :

123.22998046875112

هل لاحظت أين وقع التغيير ؟!

قد يتبادر السؤال التالي إلى ذهنك, حول السطر التالي :

y = *p;

لماذا تمت العملية دون مشاكل و أصبحت y تساوي 79.0 ؟

الجواب لأني كما قلت في الرد الأول هذا يسمى implicit conversion :) و لن يكون هناك مشاكل عند التحويل من int إلى double....

أي أن المترجم يعرف مالمفروض عمله ...

عذراً أحس أن كلامي غير واضح بشكل كافي لذلك إن كان هناك سؤال فتفضل ...

تحياتي ,,

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 1 مارس 2009 في 23:28

#7

أحسنت أستاذي Khaled.Alshaya كفيت ووفيت .... أنا توقعت نفس الشيء لأني أعرف إن الـ double يخزن على طريقة 754 IEEE لكن أشكل علي التطبيق الفعلي في الذاكرة ...... وأنت وضحت ذلك فجزاك الله خيرا ....

الأخ أحمد .. هي فعلا العملية غير أمنة لكن أنا أردت الفهم الواقعي وخاصة بين int و double .... جزاك الله خيرا

#8

الله يعطيك العافية مثل ما توقعة

لكن فية سؤال هل يختلف حجم المؤشر من نوع int عن double ???

تم تعديل هذه المشاركة بواسطة almstshar2 في 3 مارس 2009 في 16:46

#9

السلام عليكم ورحمة الله وبركاته

حجم المؤشر يتبع الـPlatform .

مواضيع مشابهة