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

لغز Const - هل عندك تفسير؟

بدأه سمسوما في 30 أغسطس 2008 · 15 رد · 1,599 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. int main(int argc, char* argv[])
  6. {
  7. const int Constant = 100;
  8. int NonConstant;
  9. int* pConstant;
  10. int* pTemp;
  11.  
  12. pConstant = (int*) &Constant;
  13. *pConstant = 200;
  14.  
  15. pTemp = (int*) &Constant;
  16. NonConstant = *pTemp;
  17.  
  18. cout << "Constant: " << Constant << endl;
  19. cout << "NonConstant: " << NonConstant << endl;
  20.  
  21. system("pause");
  22. return 0;
  23. }
  24.  

ما نتيجة البرنامج ؟ وما تفسيرك لهذه النتيجة؟

تم تعديل هذه المشاركة بواسطة سمسوما في 30 أغسطس 2008 في 20:18

#2

بدون استعانه بمترجم ، والا ما الفائده من اللغز ...

ربما الناتج يكون :

Constant = 100

NonConstant =200

بدون سبب :lol:

الثابت لن يتغير حتى لو حولناه مؤقتا الى مؤشر واسندناه الى مؤشر أخر وغيرنا قيمه ذلك المؤشر ..

ربما ، لا أعلم ...

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#3

هذا الحل مبنى على اعتقاد و تخيل ...

_____________________________

المشكلة فى عدم تعريف المؤشر pConstant على انه مؤشر ثابت فعندما جعلناه يشير الى الثابت Constant لم يستطع تغيير قيمته لكنه غير القيمة التى فى العنوان التى حملها فيما بعض المتغير NonConstant

اعتقد انى بألف :lol:

#4

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

فعلا لغز محير

نتيجة البرنامج هى

Constant =100

NonConstant=200

وأعتقد أن تفسير الناتج موجود فى التحويل

(int*)

فهذا التحويل ينتج مرجع غير ثابت للثابت

Constant

وأعتقد أن التفسير أن البرنامج تعامل مع

Constant

قبل التحويل وبعده مثلما يتعامل مع المتغيران الجلوبال والمحلى

عندما يكون لهم نفس الإسم

بمعنى هى فكرة تغير فى مدى المتغيرات

وللحين أنا غير متأكد للتفسير هذا

وشكرا لك

ومنتظر التفسير الصحيح على أحر من الجمر :haha:

ولعل البرنامج الآتى يوضح فكرتى


using namespace std;
int main(int argc, char* argv[])
{
const int Constant = 100;
{
int Constant=200;
int*p2=(int*)&Constant;
int *p1=(int*)&Constant;
cout<<*p1<<endl;
cout<<*p2<<endl;
}
cout<<Constant<<endl;;
system("pause");
return 0;
}
#include <iostream>

تم تعديل هذه المشاركة بواسطة amin_mu123 في 30 أغسطس 2008 في 22:12

اللهم صل على سيدنا محمد وعلى آله وصحبه وسلم

#5

اشكرك اخي / اختي سمسوما , على هذا اللغز .

بالنسبة لي انا فارى التالي :

يتكون النتائج طبعا 100 , 200

والتفسير:

عند الاعلان عن المتغير Constant بأنه const هذا يعني ان القيمة التي يحملها المتغير لا تتغير , ولكن عند استخدام التعليمة التالية :

	*((int*) (&Constant))=200;

ستتغير القيمة التي يحملها عنوان المتغير Constant , ولكن عند محاولة طباعة المتغير فان الناتج سيعود إلى القيمة التي اعطيت للمتغير عند الاعلان عنه مسبقا , اي 100 , لكن عند طباعة القيمة التي يحملها عنوان المتغير

(*(int*)(&Constant))

ستكون القيمة 200 .

لذلك تم اسناد هذه القيمة للمتغير NonConstant حتى يتم طباعتها , وعندما تم طباعتها فعلا تم طباعة 200 , لكن عندما تم طباعة المتغير Constant فإنه سيتم العودة للقيمة المسندة عند التعريف , 100 .

تحياتي . . .

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#6
اقتباس
ستتغير القيمة التي يحملها عنوان المتغير

Constant

بصراحه هذا لغز آخر

بالنسبة الى

:wacko:

اللهم صل على سيدنا محمد وعلى آله وصحبه وسلم

#7

الي وجدته أن

(int*)&Constant;
&Constant

لهما نفس العنوان لكن عند اخذ قيمتهما تختلف


*(int*) &Constant;

*(&Constant)

اي ان العنوان يحمل قيمتين

ننتظر رد صاحب السؤال

tvquran_6.gif

#8

السلام عليكم

لاحظوا معى هذا التعديل



using namespace std;

int main(int argc, char* argv[])
{
const int Constant = 100;
const int* tmp=&Constant;
int NonConstant;
int* pConstant;
int* pTemp;
cout<<*(tmp)<<endl;
pConstant = (int*) tmp;
*pConstant = 200;
cout<<*(tmp)<<endl;
pTemp = (int*) tmp;
cout<<*(tmp)<<endl;
NonConstant = *pTemp;
cout<<*(tmp)<<endl;


cout << "Constant: " << Constant << endl;
cout << "NonConstant: " << NonConstant << endl;

system("pause");
return 0;
}
#include <iostream>

المؤشر

tmp

فى البدايه يجب أن يكون مؤشر ثابت لكى يشير الى ثابت وبعد إجراء التحويل

int*

على المؤشر

tmp

يتحول من مؤشر ثابت الى مؤشر عادى متغير

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

أما فى حالة وجود مؤشر متغير يشير الى الثابت فإن طبيعة الثابت تتغير الى متغير عادى

وهكذا

ولكنى اريد الجواب الصحيح

وبشده

:wacko:

تم تعديل هذه المشاركة بواسطة amin_mu123 في 31 أغسطس 2008 في 01:08

اللهم صل على سيدنا محمد وعلى آله وصحبه وسلم

#9

لا يتم اعطاء cout قيمة Constant الحقيقية بل القيمة الابتدائية فقط , أي يتم دفع القيمة 100 مباشرة دون النظر الى قيمة Constant بالذاكرة !

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#10

العنوان واحد لـConstant والقيمة ايضا واحدة ويمكن تغييرها عن طريق تحميل قيمة الى مؤشر للثابت , الفرق انه عند استخدام الثابت مباشرة لا يتم استخراج قيمته الحقيقية من الذاكرة بل يفضل المترجم ان يتم استخدام القيمة الابتدائية للثابت لأن ذلك يقلل حجم الملف الناتج , لكن عند استخدام مؤشر له فيكون الوضع طبيعي.

تم تعديل هذه المشاركة بواسطة GamingMasteR في 31 أغسطس 2008 في 03:21

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#11

لمن يهتم , بعض التحليل بالاسمبلي يؤكد ما قيل في الشاركة السابقة :

[color= #ff007f;]push [color= #7f7f40;]ebp

[color= #ff007f;]mov [color= #7f7f40;]ebp[color= #0000ff;],[color= #7f7f40;]esp

[color= #ff007f;]sub [color= #7f7f40;]esp[color= #0000ff;],[color= #ff0000;]0x210

[color= #ff007f;]mov [color= #0000a0; font-weight: bold;][Constant[color= #0000a0; font-weight: bold;]][color= #0000ff;],[color= #ff0000;]0x64

[color= #ff007f;]lea [color= #7f7f40;]eax[color= #0000ff;],[color= #0000a0; font-weight: bold;][Constant[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]mov [color= #0000a0; font-weight: bold;][pConstant[color= #0000a0; font-weight: bold;]][color= #0000ff;],[color= #7f7f40;]eax

[color= #ff007f;]mov [color= #7f7f40;]ecx[color= #0000ff;],[color= #0000a0; font-weight: bold;][pConstant[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]mov [color= #aa007f;]dword [color= #7f00ff;]ptr [color= #0000a0; font-weight: bold;][[color= #7f7f40;]ecx[color= #0000a0; font-weight: bold;]][color= #0000ff;],[color= #ff0000;]0xc8

[color= #ff007f;]lea [color= #7f7f40;]edx[color= #0000ff;],[color= #0000a0; font-weight: bold;][Constant[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]mov [color= #0000a0; font-weight: bold;][pTemp[color= #0000a0; font-weight: bold;]][color= #0000ff;],[color= #7f7f40;]edx

[color= #ff007f;]mov [color= #7f7f40;]eax[color= #0000ff;],[color= #0000a0; font-weight: bold;][pTemp[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]mov [color= #7f7f40;]ecx[color= #0000ff;],[color= #aa007f;]dword [color= #7f00ff;]ptr [color= #0000a0; font-weight: bold;][[color= #7f7f40;]eax[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]mov [color= #0000a0; font-weight: bold;][NonConstant[color= #0000a0; font-weight: bold;]][color= #0000ff;],[color= #7f7f40;]ecx

[color= #ff007f;]push [color= #ff0000;]0x64		[color= #007f00; font-style: italic;];=======================> يتم دفع القيمة 100 مباشرة وليس قيمة الثابت Constant

[color= #ff007f;]push [color= #7f00ff;]offset str_constant

[color= #ff007f;]push [color= #7f00ff;]offset [color= #ff007f;]std[color= #0000ff;]::cout

[color= #ff007f;]call [color= #ff007f;]std[color= #0000ff;]::cout_string

[color= #ff007f;]add [color= #7f7f40;]esp[color= #0000ff;],[color= #7f7f7f;]8

[color= #ff007f;]mov [color= #7f7f40;]ecx[color= #0000ff;],[color= #7f7f40;]eax

[color= #ff007f;]call [color= #ff007f;]std[color= #0000ff;]::cout_integer

[color= #ff007f;]mov [color= #0000a0; font-weight: bold;][local[color= #7f7f7f;].62[color= #0000a0; font-weight: bold;]][color= #0000ff;],[color= #7f7f40;]eax

[color= #ff007f;]push [color= #ff0000;]0xa

[color= #ff007f;]mov [color= #7f7f40;]ecx[color= #0000ff;],[color= #0000a0; font-weight: bold;][local[color= #7f7f7f;].62[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]call [color= #ff007f;]std[color= #0000ff;]::endl

[color= #ff007f;]mov [color= #7f7f40;]ecx[color= #0000ff;],[color= #0000a0; font-weight: bold;][local[color= #7f7f7f;].62[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]call [color= #ff007f;]std[color= #0000ff;]::flush

[color= #ff007f;]mov [color= #7f7f40;]edx[color= #0000ff;],[color= #0000a0; font-weight: bold;][NonConstant[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]push [color= #7f7f40;]edx	[color= #007f00; font-style: italic;];=========> يتم دفع قيمة NonConstant والتي بدورها تساوي Constant والتي تساوي 200

[color= #ff007f;]push [color= #7f00ff;]offset str_nonconstant

[color= #ff007f;]push [color= #7f00ff;]offset [color= #ff007f;]std[color= #0000ff;]::cout

[color= #ff007f;]call [color= #ff007f;]std[color= #0000ff;]::cout_string

[color= #ff007f;]add [color= #7f7f40;]esp[color= #0000ff;],[color= #7f7f7f;]8

[color= #ff007f;]mov [color= #7f7f40;]ecx[color= #0000ff;],[color= #7f7f40;]eax

[color= #ff007f;]call sdt[color= #0000ff;]::cout_integer

[color= #ff007f;]mov [color= #0000a0; font-weight: bold;][local[color= #7f7f7f;].132[color= #0000a0; font-weight: bold;]][color= #0000ff;],[color= #7f7f40;]eax

[color= #ff007f;]push [color= #ff0000;]0xa

[color= #ff007f;]mov [color= #7f7f40;]ecx[color= #0000ff;],[color= #0000a0; font-weight: bold;][local[color= #7f7f7f;].132[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]call [color= #ff007f;]std[color= #0000ff;]::endl

[color= #ff007f;]mov [color= #7f7f40;]ecx[color= #0000ff;],[color= #0000a0; font-weight: bold;][local[color= #7f7f7f;].132[color= #0000a0; font-weight: bold;]]

[color= #ff007f;]call [color= #ff007f;]std[color= #0000ff;]::flush

[color= #ff007f;]push [color= #7f00ff;]offset pause

[color= #ff007f;]call system

[color= #ff007f;]add [color= #7f7f40;]esp[color= #0000ff;],[color= #7f7f7f;]4

[color= #ff007f;]xor [color= #7f7f40;]eax[color= #0000ff;],[color= #7f7f40;]eax

[color= #ff007f;]mov [color= #7f7f40;]esp[color= #0000ff;],[color= #7f7f40;]ebp

[color= #ff007f;]pop [color= #7f7f40;]ebp

[color= #ff007f;]ret

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#12
amin_mu123 كتب:
اقتباس
ستتغير القيمة التي يحملها عنوان المتغير

Constant

بصراحه هذا لغز آخر

بالنسبة الى

:wacko:

اقصد انه باستخدام التعليمة

*((int*) (&Constant))=200;

تغيرت القيمة التي يحملها عنوان المتغير Constant لذلك عندما تعطي القيمة الموجودة بالعنوان لمؤشر فانه سيأخذ القيمة الموجودة في الذاكرة فعليا , لكن عندما تحاول طباعة قيمة المتغير Constant او اعطائها لمتغير اخر فانه سيتم اعطاء القيمة التي تم اعطائها للمتغير عندما تم التصريح عنه , لذلك نقول بان قيمة المتغير الذي يتم الاعلان عنه على انه Const لا تتغير .

هذا والله اعلم . . .

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#13

شكرا لك أخى

أنا اللى فهمته أن عنوان الثابت Constant فى الذاكره يتعامل معه الكمبيلر ( فى اللغز أقصد) بطريقتين:

اذا كان استدعاء قيمة العنوان تستدعى من خلال اسم الثابت أو مؤشر ثابت يشير اليه فإن القيمه الأصليه هى التى تأتى

أما اذا كان من خلال مؤشر متغير يشير الى نفس العنوان فأن العنوان يعود بالقيمه التى ادخلت فيه من خلال مؤشر متغير

أى يتم التعامل مع Constant على انه متغير عادى

وبارك الله فيك

اللهم صل على سيدنا محمد وعلى آله وصحبه وسلم

#14

@ Wajdy Essam

الناتج الذى توقعته صحيح، اما سبب ذلك فتابع معى

--------------

@Omar Eladel

ما ذكرته هو فعلاً ما يحدث واستنتاجك صحيح، تابع معى

--------------

@amin_mu123

الناتج الذى ذكرته صحيح، اما سبب ذلك فتابع معى

--------------

@time1

الناتج الذى ذكرته صحيح، اما سبب فأنت تدور حول السبب الصحيخ وقريب منه، تابع معى

--------------

@فهدالشلوي

ما ذكرته فى ردك صحيح، اما سبب ذلك فتابع معى

--------------

@GamingMasteR

ما ذكرته فى ردك صحيح، والتفسير أيضاً صحيح

-------------- -------------- --------------

عند تعريف المتغير انه const فإن المترجم يتعامل مع المتغبر وكأنه ثابت (مثل define#) وليس متغير (بقدر المستطاع)

ولكن لا يمكن اعتباره مثل تعريف جملة define# تماماً، حيث يتم حجز مكان للـ const فى الذاكرة، وقد استخدمنا عنوانه فى المثال

وايضاً لا يمكن اعتباره متغير عادى ، حيث غير مسموح بتغير قيمته

ولكن هو مزبج بين الاثنين

فهو يشبه تعريف define# فى أن المترجم عند التعامل معه يستخدم ثيمته الابتدائية مباشرتاً ولا يشير الى موضعه فى الذاكرة (مثل المتغبر العادى)

وبشبه المتغير العادى فى ان المترجم يحجز له عنوان فى الذاكرة (ولكن لا يستخدمها بقدر المستطاع، وسوف نرى كيف نجبر المترجم على استخدامها)

تتبع معى خطوة بخطوة: فى VC++ 6.0

- ضع Break point عند السطر (cout << "Constant: " << Constant << endl)

- شغل البرنامج بالضغط على F5

- انتظر حتى يتوقف عند سطر Break point

- أضغط Atl + 8 لمشاهدة الكود بالاسمبلى

- ستلاحظ ان المترجم يضع القيمة الابتدائية للمتغبر فى المكدس (stack) وليس ما يحتويه عنوانه، بمعنى انه يضع فى المكدس رقم ثابت بالتعليمة: push 64h

post-169176-1220282213_thumb.jpg

- عدل تعريف المتغير Constant من const int الى متغير عادى int (ليس ثابت)

- كرر نفص الخطوات السابقة

- ستلاحظ ان المترجم يضع القيمة الموجودة فى عنوان المتغبر داخل المكدس (stack)، بالتعليمات الموضحة فى الصورة

post-169176-1220282222_thumb.jpg

لاجبار المترجم استخدام مؤشر الثابت ، عدل البرنامج

  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. void printConst(const int* c)
  6. {
  7. cout << "PrintConst: " << *c << endl;
  8. }
  9.  
  10. int main(int argc, char* argv[])
  11. {
  12. const int Constant = 100;
  13. int NonConstant;
  14. int* pConstant;
  15. int* pTemp;
  16.  
  17. pConstant = (int*) &Constant;
  18. *pConstant = 200;
  19.  
  20. pTemp = (int*) &Constant;
  21. NonConstant = *pTemp;
  22.  
  23. printConst(&Constant);
  24. cout << "Constant: " << Constant << endl;
  25. cout << "NonConstant: " << NonConstant << endl;
  26.  
  27. system("pause");
  28. return 0;
  29. }
  30.  

وهنا لا يستطيع المترجم التعامل مع const على انه ثايت مطلق ولكن سيتعامل مع عنوانه فى الذاكرة مثل المتغير (جرب تنفيذ الكود ولاحظ نتيجة التنفيذ)

للحصول على الكود كامل للبرنامج بلغة الاسمبلى:

- اضغط على Alt + F7 أو اختر Settings من قائمة Project

- أختر التبويب ++C/C

- من القائمة المسدلة Category أختر Listing Files

- من القائمة المنسدلة Listing file type أختر Assembly with Source code

- أعد ترجمة البرنامج بالشغط على F7

- ستجد فى المجلد Debug أو Release ملف بأيم كل ملف فى البرنامج بالامتداد asm يحتوى على كود السى والاسمبلى يكون مفيد للدراسة

post-169176-1220282228_thumb.jpg

الى اللقاء فى الغاز قادمة

#15
اقتباس
فهو يشبه تعريف define# فى أن المترجم عند التعامل معه يستخدم ثيمته الابتدائية مباشرتاً ولا يشير الى موضعه فى الذاكرة (مثل المتغبر العادى)

That what am I say :wink:

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#16

حقيقة أستفدنا من هذا اللغز معلومه قيمة ومفيده باسلوب جميل.

في أنتظار جديدك .

tvquran_6.gif

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