الشبكة العربية لمطوري الألعاب

محترف مشرف عبد اللطيف حاجي علي مشاركة 21

وفي 23 شباط 2009 02:46 م، ظهر شبح ابتسامة على وجه سلوان الهلالي وهو يقول:

السبب هو وجود إجراء بنفس الإسم في windows.h

كلامك صحيح إلى حد كبير. لكن ليس تماماً ☺ . السبب ليس وجود أجراء بنفس الاسم ولكن وجود تعريف ما قبل الترجمة (preprocessor #definition) للكلمة FormatMessage على أنها FormatMessageW (أو FormatMessageA في حال لم يكن UNICODE معرفاً). لذلك فإن الـ preprocessor قام باستبدال الكلمة FormatMessage في UserOutput.cpp بكلمة أخرى (FormatMessageW أو FormatMessageA) وفجأة لم نعد نعرف إجراءً باسم FormatMessage 😲 (يبدو هذا الأمر واضحاً في رسائل الخطأ التي وضعها أنس) ولذلك فإن المترجم (الـ linker في هذه الحالة) حين قام بالبحث عن تعريف هذا الإجراء لنداءه من ملف Test.cpp لم يجده وأصدر هذا الـ linking error 😄 .
حسناً... في الحقيقة كان لدي عدة أهداف من طرح هذه الأسئلة ☺ . أولاها هو التأكيد على ضرورة الانتباه إلى التحذيرات التي يخرجها المترجم. حيث يمكنكم ملاحظة أنني وضعت المحدد /W0 بين المحددات التي مررتها للمترجم. مما يمنع المترجم  من إظهار أي تحذير. فلو أنني لم أضع هذا المحدد لظهر لي التحذيران التاليان:

1>.\UserOutput.cpp(11) : warning C4003: not enough actual parameters for macro 'max'
1>.\UserOutput.cpp(12) : warning C4003: not enough actual parameters for macro 'min'

وهما يقولان صراحة أن min و max معرفان كماكرو. مما يعطينا فكرة كبيرة عن الحل 😄 .
أعلم أن قلة من المبرمجين يقومون بإلغاء جميع التحذيرات. إلا أن كثرة وخاصة المبتدئين منهم يقومون بتجاهل أي تحذير ضمنياً على أنه "كلام فارغ" ولا يمنع البرنامج من التنفيذ 😳 .

الهدف الثاني هو التأكيد على الحقيقة البسيطة: “macros are evil” 🙁 . أي أن الماكرو في C++ شر مطلق. وهذا ما ظهر جلياً حين استخدمنا بكل براءة متغيرات أو إجراءات ذات أسماء منطقية وظهرت لنا كل هذه الأخطاء دون رسائل مفيدة تقول أننا نستخدم كلمة معرفة مسبقاً مما قد يوقعنا في دوامة كبيرة (حين وقعت في هذا الخطأ كان المشروع أكبر من هذا بعشرين مرة وكنت قد استخدمت هذه الكلمات بشكل أكبر بكثير. لا زلت حتى اليوم ألوم Microsoft على صلعي بعد هذه الحادثة 😢 ). المشكلة أن الماكرو في C++ لا يحترم الـ scope ولا الـ redefinition ولا حتى الـ typing وينصح دوماً بالابتعاد عن الماكرو والاستعاضة عنه بــ typedefs و templates. وفي حال كون استخدام الماكرو ضرورياً فينصح باستخدام اسماء معقدة وطويلة وبحروف كبيرة وذلك حتى نقلل نسبة الخطأ التي حدثت ☺ . والقيام بـ #undef لاسم الماكرو حالما تنتهي من استخدامه.

عبد اللطيف حاجي علي
مبرمج
In|Framez

محترف مشرف عبد اللطيف حاجي علي مشاركة 22

أما في 22 شباط 2009 09:23 م، فقد تنهد انس بارتياح وهو يرد:

السلام عليكم

لا املك جوابا لهدا السؤال لكن اردت ان اير ان مترجم  GCC يشير الى وجود خطا في هدا السطر .
typedef (std::vector::const_iterator)  iterator;
يبدو يا أنس أنك أضفت قوسين حول "std::vector::const_iterator" لم يكونا موجودين في الـ code الأساسي.

الخطأ الثاني هو سهو من جهتي أعتذر عنه بشدة. لإصلاحه فقط استبدل آخر سطر في FormatMessage بما يلي:
char szBuffer[64];
wsprintf(szBuffer, TEXT("Minimum of array is: %d\n")
	TEXT("Maximum of array is: %d\n"), min, max);

أعتذر مرة أخرى.
ملاحظة: الـ code المكتوب هنا في أغلب الأحيان ليس أفضل ما يمكن كتابته (كنت استخدمت std::string هنا لو كنت في مشروع حقيقي) إلا أنني تعمدت استخدام wsprintf لأشرح النقاط المذكورة.

عبد اللطيف حاجي علي
مبرمج
In|Framez

موهوب  عبدالله الشمّري مشاركة 23

المشكلتين التي ذكرت حتّى الان , تعرّضت لها سابقا  , وشيّبت رأسي ( لم اصل لدرجة الصلع☺ ) , خاصة مشكلة الـ Constructor , وفي مشاريع ليست صغيرة !! ... فاختيارك للمشاكل موفّق بإّذن الله , وننتظر مزيد من المشاكل :-) .

--
طالب - تخصص نظم معلومات .
--

محترف مشرف عبد اللطيف حاجي علي مشاركة 24

مشكلة جديدة.
اللغة: C++
الصعوبة: سهل
المطلوب: السبب واقتراح للحل.
الشرح:

الـ code التالي (غير قابل للترجمة) يعطي نتائج مختلفة بين الـ release و الـ debug.
 
#if !NDEBUG
	#define MY_ASSERT(x)	if (!x) fail(__FILE__, __LINE__);
#else
	#define	MY_ASSERT(x)	// Nothing
#endif

typedef std::vector ByteArray;

bool DecodeMsg(const ByteArray& arrMsg)
{
	/* Message Format
	2 bytes: Width (little endian)
	2 bytes: Height (little endian)
	1 byte: Data Order. Always 1 (R then G then B)
	1 bytes: Bits per pixel
	n bytes: Pixles
	*/
	ByteArray::const_iterator itr = arrMsg.begin();

	// 2-bytes witdh
	unsigned char c1 = *itr++, c2 = *itr++;
	m_Width = c1 | (c2 << 8);
	MY_ASSERT(m_Width != 0);

	// 2-bytes height
	c1 = *itr++; c2 = *itr++;
	m_Height = c1 | (c2 << 8);
	MY_ASSERT(m_Height != 0);

	// 1-byte version. Always 1
	MY_ASSERT(*itr++ == 1);

	// 1-byte BPP
	m_BPP = *itr++;
	MY_ASSERT(m_BPP == 8 || m_BPP == 16 || m_BPP == 24);

	// Continue to read pixels
}

هل يمكنك معرفة السبب؟ 😒

عبد اللطيف حاجي علي
مبرمج
In|Framez

محترف  انس مشاركة 25

سلام


ان تصرف البرنامج لا يختلف عادة سواء بني ب  debug ou release  الا ادا حددنا مناطق من الكود ب  preprocesseur



#if !NDEBUG  //  ادا كان البناء ب  debug 
	#define MY_ASSERT(x)	if (!x) fail(__FILE__, __LINE__);
#else // ادا كان ب  release
	#define	MY_ASSERT(x)	// Nothing
#endif


 يعني ستختلف الدالتان (و لو كانت هي دالة واحدة في الحقيقة) و بالتالي تعطي نتائج مختلفة .


هده الطريقة تستعمل ايضا في المكتبات لجعلها تعمل على منصات مختلفة .


ملاحظة الكود لا يترجم بمترجم  GCC :

D:\Nouveau dossier\test\main.cpp|10|error: expected initializer before "ByteArray"|
D:\Nouveau dossier\test\main.cpp|12|error: expected `,' or `...' before '&' token|
D:\Nouveau dossier\test\main.cpp|13|error: ISO C++ forbids declaration of `ByteArray' with no type|
...
||=== Build finished: 14 errors, 5 warnings ===|



سلام

محترف مشرف عبد اللطيف حاجي علي مشاركة 26

في 23 شباط 2009 06:58 م، قال انس بهدوء وتؤدة:

ان تصرف البرنامج لا يختلف عادة سواء بني ب  debug ou release  الا ادا حددنا مناطق من الكود ب  preprocesseur
نعم كلامك سليم☺ . من الطبيعي أن يختلف البرنامج في هذه الحالة. لكني أستخدم مبدأ الـ assert (يمكنك البحث عنه أو السؤال في موضوع منفصل) والذي يجب ألا يأثر على سير البرنامج. أو هكذا يفترض 😒 ؟؟!!

في 23 شباط 2009 06:58 م، عقد انس حاجبيه بتفكير وقال:

ملاحظة الكود لا يترجم بمترجم  GCC :
ولن يترجم بأي مترجم 😲 .

وفي 23 شباط 2009 06:32 م، قال عبد اللطيف حاجي علي متحمساً:

الـ code التالي (غير قابل للترجمة) يعطي نتائج مختلفة بين الـ release و الـ debug.
( على كلٍ يبدو أن نظام إرسال الرسائل قد قام بحذف القوسين <> و ما يتبعهما قبل ByteArray)

عبد اللطيف حاجي علي
مبرمج
In|Framez

محترف  انس مشاركة 27

سلام

اريد ان اطرح سؤالا ....

هل قمت بتعريف :



#include 
او 
#include 

ادا لم تقم بتعريفهما فان السطر التالي لن يقوم بشيئ ف debug

#else // ادا كان ب  debug
	#define	MY_ASSERT(x)	// Nothing

in release mode : سيكون للماكرو دور .

محترف مشرف عبد اللطيف حاجي علي مشاركة 28

على العكس تماماً 😄 . هذا الـ code:
#if !NDEBUG  //  ادا كان البناء ب  debug 
	#define MY_ASSERT(x)	if (!x) fail(__FILE__, __LINE__);
#else // ادا كان ب  release
	#define	MY_ASSERT(x)	// Nothing
#endif
Write Code Here

يقوم بتفعيل الـ assert في وضع الـ debug. أما في وضع الـ release فإن جميع التحققات التي تستخدم assert سوف لن تحدث وذلك ليكون البرنامج أسرع ☺ .

لاحظ أنني لا أضم assert.h ولا cassert.h وذلك لأنني أعرّف إصداري الخاص من الـ assert والذي دعوته MY_ASSERT (لاحظ استخدامي لحروف كبيرة وكلمة طويلة لكي لا أربك المستخدم)

عبد اللطيف حاجي علي
مبرمج
In|Framez

محترف  انس مشاركة 29

وفي 23 فبراير 2009 06:09 م، ظهر شبح ابتسامة على وجه عبد اللطيف حاجي علي وهو يقول:

يقوم بتفعيل الـ assert في وضع الـ debug.

لقد تم تصحيح الخطا في المشاركة السابقة.

حسنا ... ادا بما ان التفعيل تم في release mode  فان برنامجك قد يتوقف عن العمل ادا كانت احدى عبارات التي ارسلتها ل  MY_ASSERT خاطئة
اما في الحالة العكسية ... فلن يتوقف الرنامج لان MY_ASSERT  لا تقوم بشيئ

موهوب  عبدالله الشمّري مشاركة 30

سؤال خارج الموضوع قليلا لو سمحت :


ماذا تقصد في الكود التالي :

أما في 28/صفر/1430 06:09 م، فقد تنهد عبد اللطيف حاجي علي بارتياح وهو يرد:

m_Width = c1 | (c2 << 8

أقصد ماهو عمله ..

--
طالب - تخصص نظم معلومات .
--