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

سؤال حول const_cast

بدأه khaled_prg في 8 أكتوبر 2010 · 7 رد · 614 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

للذهاب إلى الموضوع الأصلي.

قمت بكتابة هذا الموضوع الجديد لأن الأسئلة أصبحت مستقلة عن فحوى الموضوع الأصلي (الأسئلة ترتكز على الدالة فقط و خصوصا المؤشرات !)

كود الدالة :

bool isNumber(const char* str)
{
        char *pMove = const_cast<char*>(str);

        while(*pMove)
                if (*pMove < 0x30 || *pMove > 0x39)
                        return false;
                else
                        pMove++;

        return true;
}

خلاصة الموضوع :

أنا : ما معنى هذا السطر و ما الهدف منه !؟

char *pMove = const_cast<char*>(str);

محمد علاء الدين : حيث أن str هى مؤشر لثابت نصي لذا لا يمكن تغيير قيمة str (حيث من الممكن ان يكون str يشير لقيمة literal) و بالتالى اقوم بإستخدام const cast للحصول على قيمة المؤشر داخل متغير pMove حتى استطيع تغيير قيمة ذلك المؤشر بالزياده لاحقا.

أنا : أرجوا منك توضيح الأجزاء ذات اللون الأحمر مع شكري لك مقدما :)

ملاحظة : لا أعرف ما هو const cast ! :blush:, يا ريت لو تكون الإجابة باللغة العربية و بدون مواقع أجنبية !

____________________________________________

أنا : لم أفهم شرط حلقة التكرار :

while(*pMove)

محمد علاء الدين : معنى هذا الشرط انه يتم تنفيذ الكود طالما أن *pMove لا يساوى الصفر و ذلك لأن الصفر فى هذا المكان يعنى false اى تسبب فى انتهاء الحلقه بالإضافه ان الصفر يعنى انتهاء النص.

أنتظر إجابتكم على الأسئلة التي بالأعلى ولكن سأضيف بعض التعليقات على كلام الأستاذ محمد علاء الدين حسب فهمي و أريدكم أن تصححوا لي هذه التعليقات :

السبب وراء استخدامك لـ const cast (مع أني لا أعرفه !) هو أن str عبارة عن سلسلة حرفية ثابتة و لا يمكن لأي مؤشر أن يشير إليها !, لأن المؤشر إذا كان يشير لهذه السلسة فهذا معناه انه يمكننا تغيير "قيم خاناتها" أو "حروفها" اعتمادا على تحريك المؤشر و تغيير قيمته في كل مرة !, هل هذا التفسير صحيح !؟

اقتباس
معنى هذا الشرط انه يتم تنفيذ الكود طالما أن *pMove لا يساوى الصفر و ذلك لأن الصفر فى هذا المكان يعنى false اى تسبب فى انتهاء الحلقه بالإضافه ان الصفر يعنى انتهاء النص.

هل أفهم من كلامك أن :

الخانة الأخيرة من السلسلة الحرفية يكون فيها الرمز \0 و إذا كان المؤشر عند هذه الخانة فإن قيمته ستكون الكود آسكي المقابل للرمز السابق و تساوي 0, هل هذا صحيح !؟

ألا يمكننا استخدام سلسلة حرفية غير ثابتة مما يمكننا من إسنادها لمؤشر حرفي بشكل طبيعي بدل أن نستخدم سلسلة حرفية ثابتة !؟, انظر الكود :

bool isNumber(char* str)
{
        char *pMove = str;

        while(*pMove)
                if (*pMove < 0x30 || *pMove > 0x39)
                        return false;
                else
                        pMove++;

        return true;
}

تحياتي.

تم تعديل هذه المشاركة بواسطة khaled_prg في 8 أكتوبر 2010 في 16:54 — السبب: يمنع توجيه السؤال لشخص معين

#2

اخى الكريم

صراحه انا لم اشاهد مثل هذه الداله من قبل

const_cast<char*>(str);

لانى غير متعمق فى السى بلس بلس

لذلك اترك الامر لأصحابه

اتمنى ان يفيدك احد باذن الله

والله لو اعرف اساعدك لكنت ساعدتك

Software Developer
Mahmoudkelany.com


 

#3

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

أخ خالد, رجاءً لا توجه السؤال لأسماء معينة, هذا مخالف لقواعد المنتدى و غير لائق لمن يريد الإجابة على السؤال :)

بالنسبة لسؤالك فالدالة خاطئة للأسف, و ربما فات الأمر على الأخ محمد لا أكثر. أولاً:

bool isNumber(const char* str)

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

char *pMove = const_cast<char*>(str);

و هذا في الحقيقة يمكن أن ينتج عنه undefined behavior في حالة كون الوسيط الذي تم تمريره من نوع مؤشر متغير إلى حرف ثابت.

في السطور اللاحقة, قام بالتأكد أن كل حرف عبارة عن رقم و الأرقام في ASCII تمتد من 0x30 و هو الصفر إلى 0x39 و هو 9. و شرط الحلقة يعطينا false في حالة كون الحرف عبارة عن الـ null character و هو في الحقيقة الصفر و يكتب في الـ string literals عن طريق الـ escape character و هو 0\.

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

#include <cctype>

bool is_number(const char* number_string)
{
	while(*number_string)
	{
		if(!std::isdigit(*number_string++))
			return false;
	}
	return true;
}

و حتى هذه الطريقة ليست آمنة حقيقة, لأنك يجب أن تتحقق بعد ذلك إذا أردت تحويل النص إلى نوع عددي من كون النوع العددي يستطيع حمل الرقم أم لا و هل سيحدث overflow؟

برأيي, أفضل طريقة هي استخدام الـ streams أو كتابة دالة تستخدم الـ streams أو استخدام boost::lexical_cast.

تحياتي...

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 8 أكتوبر 2010 في 15:13

3
#4

مقبولة منك يا محمد :), بانتظار خالد الشايع و محمد علاء الدين :wink:

----------

تعديل :

جاري كتابة الرد لمشاركة الأستاذ خالد الشايع :)

بالتوفيق

تم تعديل هذه المشاركة بواسطة khaled_prg في 8 أكتوبر 2010 في 15:14

#5

السلام عليكم

في البداية .. أعتذر عن أسئلتي البدائية فأنا مبتدأ في المؤشرات :blush:

1- لاحظتُ أنكم تكتبون ان الدالة تستقبل مؤشر حرفي ثم تُرسلون إليها سلسلة حرفية !!!, كيف ذاك !؟

ألم يكن من المفترض أن ترسلوا للدالة مؤشر حرفي يشير إلى السلسة الحرفية المراد إرسالها !؟ :huh:

2- لم أفهم هذا السطر :

 if(!std::isdigit(*number_string++))

الرجاء التوضيح أكثر.

3-

اقتباس
و حتى هذه الطريقة ليست آمنة حقيقة, لأنك يجب أن تتحقق بعد ذلك إذا أردت تحويل النص إلى نوع عددي من كون النوع العددي يستطيع حمل الرقم أم لا و هل سيحدث overflow؟

هل يمكننا التحقق من أن النوع العددي يستطيع حمل الرقم أو لا !؟

اقتباس
برأيي, أفضل طريقة هي استخدام الـ streams أو كتابة دالة تستخدم الـ streams أو استخدام boost::lexical_cast.

:blink: :wacko:

ما رأيك في هذا الكود :

bool isNumber(char* str)
{
        char *pMove = str;

        while(*pMove)
                if (*pMove < 0x30 || *pMove > 0x39)
                        return false;
                else
                        pMove++;

        return true;
}

ملاحظة : لم تُجب على التعليقات التي كتبتُها بالأعلى !

بالتوفيق.

تم تعديل هذه المشاركة بواسطة khaled_prg في 8 أكتوبر 2010 في 15:50

#6
اقتباس
في البداية .. أعتذر عن أسئلتي البدائية فأنا مبتدأ في المؤشرات

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

أنا أقصد لا توجه السؤال لشخص بعينه في مكان عام, فهذا إنقاص لغير المذكورين و منهم أفضل أعضاء المنتدى, و لو كانت بالأفضلية لكان يجب أن تضع اسم وجدي عصام أولاً :)

عموماً,

اقتباس
1- لاحظتُ أنكم تكتبون ان الدالة تستقبل مؤشر حرفي ثم تُرسلون إليها سلسلة حرفية !!!, كيف ذاك !؟

كيف تتعامل مع السلسلة الحرفية في C؟ هل لديك نص و لديك حجمه؟

ببساطة, المترجم يأخذ النص و يضعه في مكان في الملف التنفيذي و يسمى غالباً Data Section. ثم يعطيك عنوان أول حرف, و نعرف نهاية النص لأن اللغة تشترط وجود null character في نهاية السلسلة الحرفية في الذاكرة. و بهذا بواسطة عنوان أول حرف نستطيع الحصول عليه كاملاً لأن لدينا علامة على نهاية النص. أما:

if(!std::isdigit(*number_string++))

فتعني أذا لم يكن الحرف الذي يمر المؤشر عليه "رقماً" بالتمثيل النصي أو ASCII فقم بإرجاع false. و ++ تعني بعد الاسم أن تمرير المؤشر إلى الدالة يكون قبل تحريك موقعه للأمام. أما بالنسبة لـ:

اقتباس
هل يمكننا التحقق من أن النوع العددي يستطيع حمل الرقم أو لا !؟

هذا مثال يعطيك ما تريد. لاحظ أن النص يجب أن يكون عبارة عن عدد فقط. يمكنك اختبار تحويل النص إلى أي نوع عددي تريده! عن طريق الـ template parameter كما في المثال:

#include <sstream>

template <typename T>
bool is_number(const char* number_string)
{
	T number;
	std::istringstream convertor(number_string);
	bool is_number = convertor >> std::noskipws >> number;
	return is_number && convertor.eof();
}

int main()
{
	bool input_is_correct = is_number<unsigned int>("11235555");
}

الكود الذي وضعته في مشاركتك جيد. و لكني أفضل طريقة الـ streams أو boost::lexical_cast.

بالنسبة لـ const_cast فإنها تقوم بإزالة const من الثابت, و تجعله متغير. و تقوم بإضافة const إلى المتغير ليصبح ثابت. أي أنها تعمل على حسب الشيء الممرر إليها إما ثابت و إما متغير.

تحياتي..

تم تعديل هذه المشاركة بواسطة Khaled.Alshaya في 8 أكتوبر 2010 في 16:31

3
#7

شكرا للأخ خالد الشايع لتصحيح الخطأ الذى وقعت فيه، و عذرا للأخ خالد على عدم الإفاده.

و الله ولي التوفيق

مدونتي: C++ Tips and Tricks

#8
اقتباس
أعتذر منك إن كنت فهمت مني ذلك. السؤال الغبي هو السؤال الذي لا تسأله أصلاً ,

لا لا لم أفهم هكذا !, فقط أردتُ تنبيهكم لكي تأخذوا عبارات مناسبة في الشرح بحيث أستطيع فهمها ! :blush:

اقتباس

أنا أقصد لا توجه السؤال لشخص بعينه في مكان عام, فهذا إنقاص لغير المذكورين و منهم أفضل أعضاء المنتدى, و لو كانت بالأفضلية لكان يجب أن تضع اسم وجدي عصام أولاً :)

انظر جيدا إلى ما كتبتُ :

اقتباس
أرجو من جميع الأعضاء المساعدة و أخص بالذكر :

خالد الشايع و محمد علاء الدين ...

ذكرت أنني أريد المساعدة من جميع الأعضاء و ذكرت اسمك و اسم محمد علاء الدين لأنني متأكد من أنكما تعرفان الإجابة و تستطيعان توصيل الفكرة, أضف إلى ذلك أنني أحب أسلوبكما في الشرح و توصيل الأفكار :wub:, بالنسبة لأستاذنا المحترف "وجدي عصام" فأنا أعرفه جيدا و يكفي من إبداعه البحث الذي ألفه عن الفيروسات و طرق القضاء عليها أضف إلى ذلك أنه كان مشرف قسم السي و السي++ و الجافا و أحد الخبراء المعتمدين رسميا من طرف إدارة الفريق و .....! :cool: , ولكنني لم أذكر اسمه لأنه لم يعد يدخل إلى هذا القسم (أو لنقل أنه نادرا ما يدخل !) .. ربما لانشغاله التام هذه الأيام و ربما لأنه يفضل الجافا :P

شرحك واضح و جميل, جزاك الله ألف خير :)

هل توافقني على هذه الفقرة :

اقتباس
الخانة الأخيرة من السلسلة الحرفية يكون فيها الرمز \0 و إذا كان المؤشر عند هذه الخانة فإن قيمته ستكون الكود آسكي المقابل للرمز السابق و تساوي 0

تحياتي.

تم تعديل هذه المشاركة بواسطة khaled_prg في 8 أكتوبر 2010 في 16:52

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