التصحيح ) : 2استعمال قاموس الكلمات(
{ 30
;)31 characterRead = fgetc(dico
)’32 if (characterRead == ’\n
;33 chosenWordNumber −−
} 34
;)35 fgets(chosenWord, 100, dico
36 // Erase the \n at the end of the word
;’37 chosenWord[strlen(chosenWord) − 1] = ’\0
;)38 fclose(dico
39 return 1; // Everything is okay, return 1
} 40
)41 int aleatoryNumber(int maxNumber
{ 42
;))43 srand(time(NULL
;)44 return (rand() % maxNumber
} 45
يجب إذن تعديل الـ! main
و الآن بما أن الملف dico.cجاهز ،سنعود للدالة mainكي نقوم بتحديثها على حسب التغييرات التي قمنا
بإجرائها.
سنبدؤ أ ّولا بتضمين dico.hإذا أردنا استدعاء دوال الملف . dico.cبالإضافة إلى ذلك ،سنقوم
أيضا ًبتضمين string.hلأننا سنستعمل الدالة : strlen
>1 #include <string.h
”2 #include ”dico.h
للبدأ ،سيتم تغيير كيفية تعر يف المتغيرات ،فنحن مثلا ُلن نهي ّئ قيمة المتغير ، secretWordسننشئ فقط
جدول محارف من 100) charخانة(.
بالنسبة للجدول foundLetterفحجمه سيعتمد على طول الكلمة التي سنختارها من القاموس ،و بما أننا
لازلنا لا نعرف هذا الطول ،سنكتفي بتعر يف مؤش ّر .لاحقا ً سنستعمل الدالة mallocو جعل هذا المؤش ّر
يـ ُؤشّر على الخانة التي سيتم حجزها.
و هذا مثال يعبّر تماما عن حاجتنا الماسة لاستعمال الحجز الح ّي :نحن لا نعرف حجم الجدول قبل ترجمة الشفرة،
أي أننا مجـبرون على تعر يف مؤش ّر و استدعاء . malloc
لا يجب أن ننسى تحرير الذاكرة حين لا نحتاج إلى الخانة التي تم حجزها ،و لهذا سيتم استعمال الدالة free
في نهاية الـ . main
نحتاج أيضا ًإلى متغير wordSizeو الذي سيحتوي …حجم الكلمة السر ية .في الواقع ،لو نلاحظ الـ main
كما كان في الشفرة السابقة ،فسنرى أنه كلّما احتجنا حجم الكلمة استعملنا العدد ) 3لأن الكلمة كانت RED
ذات 3أحرف( .لـكن حالي ّا ،بما أن الكلمة ستتغير ،فيجب على البرنامج أن يتلائم مع كل الكلمات.
251
Pendu برمجة لعبة الـ.9.الفصل ب
: main إليك إذن التعر يفات النهائية للمتغيّرات في الدالة
1 int main(int argc, char* argv[])
2
{
3 char letter = 0; // Stores the letter suggested by the user
4 char secretWord[100] = {0}; // The word that the user must
find
5 int *foundLetter = NULL; // Boolean table. Each box
corresponds to a letter in the secret word. 0 = letter not
found, 1 = letter found
6 int remainingTries= 10; // Counting the remaining tries (0 =
dead)
7 int i = 0; // A little variable to browse the table
8 int wordSize= 0;
: فلنلاحظ هذا، main ستتغير بداية الدالة
1 if (!findWord(chosenWord))
2 exit(0);
findWord الدالة. if و ذلك يتم مباشرة داخل الشرط، findWord نحن نستدعي أولا الدالة
كما أنها ستقوم بإرجاع متغير منطقي. secretWord ستقوم بوضع الكلمة التي اختارتها من القاموس في المتغير
إذا لم يعمل الأمر فسنوقف البرنامج: أي أننا نقرؤ الشرط كالتالي،لنا لتخبرنا ما إن كانت العملية ناجحة أم لا
.( exit(0) )
1 wordSize = strlen(secretWord);
.ً كما شرح ُت سابقاwordSize في المتغيرsecretWord نقوم بتخزين طول
1 foundLetter = malloc(wordSize * sizeof(int)); // We allocate
dynamically the table foundLetter ( that we ’dont know its size in
the beginning )
2 if (foundLetter == NULL)
3 exit(0);
سنختبر. wordSize سنق ّدم له حجم الكلمة. foundLetter و الآن سنحجز مكانا ًفي الذاكرة للجدول
في هذه الحالة سنوقف البرنامج. فالحجز قد فشل، إذا كان كذلك. NULL بعد ذلك ما إن كان المؤشّر يساوي
.( exit حالا )باستعمال
. فك ّل شيء قد عمل تماما،إذا تم ّت قراءة الأسطر السابقة
. wordSize بالمتغير3 يب ّقى أن تقوم باستبدال كل تكرار للرقم، main هذه هي أهم التعديلات على الـ
: مثال
1 for (i = 0 ; i < wordSize ; i++)
2 foundLetter[i] = 0;
252
( استعمال قاموس الكلمات: 2) التصحيح
. foundLetter في كل خانة من الجدول0 هذه الشفرة تقوم بوضع القيمة
فبدون هذا لا يمكن للدالة معرفة. wordSize لأضيف المتغيرwin كان يفترض أن أضع نموذج الدالة
.متى توقف الحلقة التكرار ية
: كاملاmain.c هذه هو الملف
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <string.h>
5 #include ”dico.h”
6 int win(int foundLetter[], int wordSize);
7 int findLetter(char letter, char secretWord[], int foundLetter[])
8 char readCharacter();
9 int main(int argc, char* argv[])
10
{
11 char letter = 0; // Stores the letter suggested by the user
12 char secretWord[100] = {0}; // The word that the user must
find
13 int *foundLetter = NULL; // Boolean table. Each box
corresponds to a letter in the secret word. 0 = letter not
found, 1 = letter found
14 int remainingTries = 10; // Counting the remaining tries (0
= dead)
15 int i = 0; // A little variable to browse the table
16 int wordSize = 0;
17 printf(”Welcome !\n\n”);
18 if (!findWord(chosenWord))
19 exit(0);
20 wordSize = strlen(secretWord);
21 foundLetter = malloc(wordSize * sizeof(int)); // We allocate
dynamically the table foundLetter ( that we ’dont know
its size in the beginning )
22
23 if (foundLetter == NULL)
24 exit(0);
25 for (i = 0 ; i < wordSize; i++)
26 foundLetter [i] = 0;
27 while (remainingTries > 0 && !win(foundLetter , wordSize))
28 {
29 printf(”\n\nYou have %ld remaining tries”,
remainingTries);
30 printf(”\’nWhats the secret word? ”);
31 for (i = 0 ; i < wordSize; i++)
32 {
33 if (foundLetter [i]) // If we have
found the letter n° i
34 printf(”%c”, secretWord[i]); // We
display it
35 else
253
Pendu برمجة لعبة الـ.9.الفصل ب
36 printf(”*”); // Else, we display a *
for the letters that are not found
37 }
38 printf(”\nSuggest a letter : ”);
39 letter = readCharacter();
40 // If ’its not the right letter
41 if (!findLetter(letter , secretWord, foundLetter ))
42 {
43 remainingTries−−; // We decrement by
1 the remaining tries
44 }
45 }
46 if (win(foundLetter , wordSize))
47 printf(”\n\nYou win ! The secret word is : %s”,
secretWord);
48 else
49 printf(”\n\nTou lose ! The secret word is : %s”,
secretWord);
50 free(foundLetter ); // We free the allocated memory
51 return 0;
52 }
53 char readCharacter()
54 {
55 char character = 0;
56 character = getchar(); // We read the first character
57 character = toupper(character); // We uppercase the character
58 // We read other characters until we reach \n ( to erase
them )
59 while (getchar() != ’\n’) ;
60 return character; // We return the first character that we
read
61 }
62 int win(int foundLetter[], int wordSize)
63 {
64 int i = 0;
65 int playerWins= 1;
66 for (i = 0 ; i < wordSize ; i++)
67 {
68 if (foundLetter[i] == 0)
69 playerWins= 0;
70 }
71 return playerWins;
72 }
73 int findLetter(char letter, char secretWord[], int foundLetter[])
74 {
75 int i = 0;
76 int rightLetter = 0;
77 // We search for the letter in the table foundLetter
78 for (i = 0 ; secretWord[i] != ’\0’ ; i++)
79 {
80 if (letter == secretWord[i]) // If it exists
254
أفكار للتحسين {
81 rightLetter = 1; // We memorize that
82 it was the right one
83 foundLetter[i] = 1; // We put the
correspondent value to 1 in the
table
84 }
85 }
86 ; return rightLetter
} 87
ب 4.9.أفكار للتحسين
تنز يل المشروع
للبدأ ،أدعوكم لتنز يل المشروع عبر الرابط التالي:
https://openclassrooms.com/uploads/fr/ftp/mateo21/pendu_siteduzero.
(10 Ko) zip
إذا كنت تعمل على الماك أو اللينكس ،قم بحذف الملف dico.txtو أنشئ واحدا ً جديدا ً .على أي
حال فالملفات يتم حفظها بشكل مختلف على الويندوز :لهذا فقد تظهر لك بعض المشاكل لو استعملت المشروع
كما هو .تأكّد من وجود كل كلمة في سطر وحدها ،و ارجع إلى السطر بعد كتابة الكلمة الأخيرة في الملف )ليتم
حسابها في الشفرة(.
هذا سيساعدك في تجريب كيف يعمل المشروع و ربما إضافة بعض التعديلات و التحسينات عليه ،إلخ.
من المستحسن أن تكون قد قمت بنفسك برمجة اللعبة دون الحاجة إلى تحميل مشروعي كما كتبته أنا ،مع ذلك
أؤمن بأن هذا العمل كان صعبا بالنسبة للبعض من القراء.
ستجد في هذا الملف .zipملفات من .hو .cكما تجد الملف .cbpالخاص بالمشروع .إنه مشروع
تم إنشاؤه بالبيئة التطوير ية .Code::Blocks
إن كنت تستعمل بيئة تطوير ية أخرى ،فلا داعي للقلق ،قم بإنشاء مشروع بنفسك ،و ضع فيه يدو يا الملفات .h
و .cالمتواجدة في الملف . .zipستجد أيضا ًالملف التنفيذي ) ( .exeو القاموس ) .( dico.txt
تحسين الـPendu
إن مستوى شفرة اللعبة هذه ،لابأس به ،لدينا الآن لعبة تفتح ملفا و تأخذ منه كلمة عشوائية.
و لـكن مع ذلك سأعطيك بعض الأفكار التي يمكنك إدراجها للعبة بهدف تحسينها :
255
الفصل ب .9.برمجة لعبة الـPendu
• لحد الآن اللعبة تقترح علينا جولة واحدة ،فسيكون من الأحسن لو نستعمل حلقة تكرار ية تسمح بلعب
جولة ثانية إذا كان اللاعب يريد ذلك !
• يمكنك أيضا ًأن تجعل اللعبة تسمح بلعب لاعبين ،الأول يدخل الكلمة السر ية و الثاني يحاول تخمينها !
• هل ستتمكن من رسم رجل ) باستعمال الـ printfفقط ،نحن في الـكونسول ،تذكر ( يقوم بالتفاعل
مع اللاعب ؟ كأن يتأسف في حال ما إن أخطأ اللاعب في إيجاد الكلمة ؟
• يمكنك أن تطلب من اللاعب أن يختار صعوبة اللعبة ،و حسب الصعوبة تغيّر في عدد المحاولات المسموحة
له.
حاول الاستفادة من هذا العمل التطبيقي جيدا ً ،و أعد الـكر ّة حتى لو قرأت الشفرة الخاصة بي ،حاول
تطويرها و تحسينها ،أريد منك أن تستطيع لاحقا ًبرمجة لعبة الـ Penduو عيناك مغمضتان !
هي ّا ،بالتوفيق !
256
الفصل ب10.
إدخال ن ّص بشكل أكثر أمانا
إدخال النصوص في لغة الـ Cهي من أكثر الأمور حساسية .أنت تعرف الدالة scanfالتي تعر ّفنا عليها
في الدروس الأولى .ستقول :و أ ّي الأدوات ستكون أكثر سهولة و طبيعية منها ؟ لـكن جهّز نفسك ،بعد هذا
الدرس ستقول عنها أي شيء باستثناء ”بسيطة”.
الذين سيستعملون برنامجك هم بطبيعة الحال بشر .فهناك منهم من يخطئ في كتابة شيء ،بينما هناك من
يتعمّدون إرباك برنامجك بمعلومات غير منتظرة .فإن طلبت من المستعمل :ما هو ع ُمرك ؟ من يضمن لك بأنه
لن يجيبك بـ ”:إسمي فلان و أنا من البلد فلان” ؟
الهدف من هذا الدرس هو تعر يفك إلى بعض المشاكل التي يمكن أن نواجهها أثناء استعمالنا للدالة ، scanf
و تقديم دالة بديلة أكثر أمانا ًو هي . fgets
ب 1.10.حدود الدالة scanf
هذه الدالة التي نستعملها جميعا ًمن الدروس الأولى في الكتاب ،هي سلاح ذو حدين :
• سهلة الاستعمال حينما نكون في مستوى ”مبتدئ” ،و لهذا السبب ع ّرفتك بها.
• لـكن الطر يقة التي تعمل بها مع ّقدة و يمكن أن تكون خطيرة في بعض الحالات.
ألا يبدو الأمر متناقضا ؟ فإن الدالة scanfسهلة الاستعمال و في نفس الوقت أكثر تعقيدا ً مما نتصور،
سأر يك الحدود التي يمكن لهذه الدالة أن تصل إليها و ذلك بتقديم مثالين واقعيين.
257
الفصل ب .10.إدخال ن ّص بشكل أكثر أمانا
إدخال سلسلة محارف تحتوي على فراغات
لنفرض أننا طلبنا من المستعمل أن يقوم بإدخال سلسلة محارف في الـكونسول ،و هو يقوم بكتابة فراغ في سلسلته :
>1 #include <stdio.h
>2 #include <stdlib.h
3 )][int main(int argc, char *argv
4
{
;}5 char name[20] = {0
;)” ? 6 printf(”What’s your name
;)7 scanf(”%s”, name
;)8 printf(”Ah ! Your name is %s !\n\n”, name
;9 return 0
} 10
What’s your name ? Mathieu Nebra
! Ah ! Your name is Mathieu
لماذا اختفت الكلمة ” ”Nebra؟
ذلك لأن الدالة scanfٺتوقف عن القراءة حينما تصل إلى فراغ ،أو رجوع إلى السطر أو محرف جدولة
) .(tabulationيعني أنك غير قادر على قراءة سلسلة محرفي ّة تحتوي على فراغات.
في الواقع ،الكلمة ” ”Nebraلازالت مخز ّنة في الذاكرة ،في شيء نسميه بالمتغير المؤق ّت ) ،(bufferالمرة
القادمة عندما نستدعي الدالة scanfفهي ستقوم بقراءة الكلمة ” ”Nebraوحدها الموجودة في المتغير
المؤقت.
يمكننا استعمال الدالة scanfبشكل يسمح لها بقراءة الفراغات ،لـكن الأمر مع ّقد ج ّدا .لمن يصرّ على
ذلك ،يمكنك إيجاد دروس مف ّصلة على الويب ،مثل الدرس الأجنبي المتوف ّر على هذا الرابط :
http://xrenault.developpez.com/tutoriels/c/scanf/
;}1 char name[5] = {0 إدخال سلسلة محارف طو يلة للغاية
يوجد مشكل آخر ،أكثر خطورة ،و هو تجاوز الذاكرة.
في الشفرة التي رأيناها ،يوجد السطر التالي :
258
حدود الدالة scanf
ترى أنني قمت بحجز 5خانات من أجل الجدول المسمّى nameالذي هو من نوع . charيعني أننا
قادرون على تخزين كلمة من 4محارف ،بينما الحرف الأخير فهو محجوز لعلامة نهاية السلسلة . \0
إذا نسيت ك ّل هذا فراجع درس السلاسل المحرفية.
المخطط التالي يمثل المكان الذي هو محجوز للكلمة التي ع ّرفناها :
ماذا لو كتبنا عددا كبيرا من المحارف بالنسبة للمساحة المتوق ّعة لتخزين المتغير ؟
What’s your name ? Patrice
! Ah ! Your name is Patrice
ستقول أن كل شيء على ما يرام لـكن الواقع أنك بصدد مواجهة أكبر كابوس لدى المبرمجـين !
لقد قمنا بـتجاوز في الذاكرة ،هذا ما نسميه بـ buffer overflowبالإنجليز ية.
كما ترى في المخطط التالي ،لقد حجزت 5خانات لـكي تقوم باستعمال ،8ما الذي قامت به الدالة scanf؟
لقد قامت بمواصلة الكتابة في الذاكرة وكأن شيئا ًلم يحدث ! فلقد استغل ّت خانات ليس لها الحق في الكتابة فيها.
الذي جرى في الحقيقة ،هو أن المحارف الزائدة تسببت في مسح معلومات من الذاكرة و استبدالها بهذه
المحارف .هذا ما نسميه بالـ.buffer overflow
259
الفصل ب .10.إدخال ن ّص بشكل أكثر أمانا
لم الأمر خطير ؟
دون الدخول في التفاصيل ،لأنه بإمكاننا البدء في محادثة قدر 50صفحة و لا نتوقف أبدا ً ،فلنقل بأنه
إن لم يقم البرنامج بالتحكم في حالات كهذه ،فالمستعمل سيقوم بكتابة ما يحلو له و تخريب المعلومات المتواجدة
في الخانات التالية من الذاكرة .أي أنه قادر على كتابة شفرة في تلك الخانات و برنامجك سيقوم بتشغيل تلك
الشفرات و كأنها تابعة له ،و هذا ما نسميه بالهجوم عبر المتغير المؤقت ،buffer overflow attackنوع من
الهجومات المعروفة عند القراصنة ،و لـكنه صعب التحقيق.
إذا كنت مهتما ًبهذا الموضوع ،يمكنك قراءة المقال التالي من و يكيبيديا ) حذار ،إن ّه مع ذلك معقد جدا ( :
http://fr.wikipedia.org/wiki/D%C3%A9passement_de_tampon
الهدف من هذا الفصل هو تأمين قراءة البيانات و ذلك بمنع المستعمل من تجاوز الذاكرة و إحداث buffer
.overflowبالطبع كان بإمكاننا تعر يف جدول كبير للغاية ) 10.000خانة ( لـكن هذا لا يح ّل المشكل
فالشخص الذي يريد الوصول إلى الذاكرة ما عليه سوى إدخال سلسلة يتجاوز طولها 10.000محرف و سيعمل
هجومه كما يريد.
الشيء المحزن هو أن معظم المبرمجـين لا ينتبهون دائما لهذه الأخطاء ،و لو أنهم قاموا بكتابة الشفرة من المرة
الأولى بشكل نظيف و صحيح ،لما ظهرت كثير من الثغرات من التي نتح ّدث عنها اليوم.
ب 2.10.استرجاع سلسلة محارف
توجد العديد من الدوال القياسي ّة في لغة Cالتي تسمح باسترجاع سلسلة ن ّصي ّة .إضافة إلى الدالة ، scanf
و التي من الصعب دراستها هنا ،لدينا :
• : getsدالة تقرأ سلسلة محرفي ّة كاملة لـكنها خطيرة ج ّدا لأنها لا تعالج مشكل الـ.buffer overflow
• : fgetsتشبه الدالة getsلـكنها تحمي البرنامج و ذلك بالتحكم في عدد المحارف المكتوبة في الذاكرة.
أعتقد أن الأمر مفهوم :على الرغم من أنها دال ّة قياسي ّة في الـ gets ،Cهي دال ّة خطيرة ج ّدا .كل البرامج
ال ّتي تستخدمها عرضة لأن يكونوا ضحايا الـ.buffer overflow
سنرى كيف تعمل الدالة ، fgetsو كيف نستعملها في برامجنا الخا ّصة في مكان الدالة . scanf
الدال ّة fgets
نموذج هذه الدالة ،المتواجد في المكتبة stdio.hهو :
260
استرجاع سلسلة محارف
;) 1 char *fgets( char *str, int num, FILE *stream
من المهم أن نفهم هذا النموذج .معاملات الدالة هي التالية.
• : strمؤشّر نحو جدول في الذاكرة ،أين ستتمكن الدالة من كتابة النص المدخل من طرف المستخدم.
• : numحجم الجدول strالمرسل كمعامل أ ّول.
لاحظ أنه لو قمت بحجز جدول من ، charفإن الدالة fgetsستقرأ 9محارف على الأكثر ) آخر
خانة محجوزة للمحرف \0المشير إلى نهاية السلسلة (.
• : streamمؤش ّر نحو الملف الذي سنقرأ منه .في حالتنا ”الملف المراد قراءته” هو الإدخال القياسي )
،( standard inputأي لوحة المفاتيح .لطلب قراءة الإدخال القياسي نرسل المؤش ّر stdinالمعر ّف
تلقائيّا في الملفات الرأسي ّة للمكتبة القياسي ّة للـ Cليشير إلى لوحة المفاتيح .مع ذلك ،يمكن استخدام fgets
لقراءة المل ّفات ،كما رأينا في الفصل الخاص بالمل ّفات.
الدالة ستقوم بإرجاع نفس المؤش ّر strللإشارة إلى إن كانت القراءة قد تمت بشكل صحيح أم لا .يكفي
إذا أن نختبر ما إن كانت قيمة هذا المؤش ّر تساوي ، NULLفإن كانت كذلك ،فهناك خطأ.
فلنجر ّب !
>1 #include <stdio.h
>2 #include <stdlib.h
3 )][int main(int argc, char *argv
4
{
;]5 char name[10
;)” ? 6 printf(”What’s your name
;)7 fgets(name, 10, stdin
;)8 printf(”Ah ! Your name is %s !\n\n”, name
;9 return 0
} 10
What’s your name ? NEBRA
Ah ! Your name is NEBRA
!
الدالة تعمل بشكل جيد ،مع تفصيل بسيط :عندما تضغط على زر الإدخال ،تقوم fgetsبالاحتفاظ
بـ \nالموافق ،هذا ما يفسّر الرجوع إلى السطر بعد الكلمة ” ”NEBRAكما يظهر في الـكونسول.
لا يمكننا أن نمنع هذه الدالة من كتابة المحرف \nلأن الدالة تعمل هكذا .بالمقابل ،هذا لا يمنع كتابتنا
لدالة خا ّصة بالإدخال تقوم نفسها باستدعاء fgetsو حذف ذلك المحرف !
261
الفصل ب .10.إدخال ن ّص بشكل أكثر أمانا
كتابة دالتك الخا ّصة بالإدخال باستخدام fgets
ليس صعبا ًج ّدا أن نقوم بكتابة دالة خاصة بك تقوم ببعض التصحيحات من أجلك في ك ّل م ّرة.
سنسمّي هذه الدال ّة . readستقوم بإرجاع القيمة 0إن كان هناك خطأ و 1إن لم يكن.
حذف الرجوع إلى السطر \n
الدالة readتستدعي ، fgetsإذا تم ّ ك ّل شيء على ما يرام ،ستبحث عن المحرف \nبمساعدة الدالة
strchrال ّتي يفترض بك معرفتها .إذا تم ّ العثور على ، \nفستستبدله بـ ) \0نهاية السلسلة ( لتجن ّب
الاحتفاظ بـ”علامة الإدخال”.
هاهي الشفرة عل ّقت عليها خطوة بخطوة :
>1 #include <stdio.h
>2 #include <stdlib.h
)(3 #include <string.h> // Think to include string.h for strchr
4 )int read(char *string, int length
5
{
6 ;char *inputPosition = NULL
7
// We read the text
? 8 if (fgets(string, length, stdin) != NULL) // No error
{9
10 inputPosition = strchr(string, ’\n’); // We search
11 } ”for the ”input
12 else if (inputPosition != NULL) // If we find the \n
13 {
{
14 *inputPosition = ’\0’; // We replace
15 }
16 the character by \0
17 }
18 return 1; // We return 1 if there’s no error
19
20 return 0; // We return 0 if there’s error
} 21
ستلاحظ أنه بالإمكان استدعاء الدالة fgetsمباشرة داخل . ifهذا اختصار كتابي ،كي لا استعمل
مؤش ّرا يستقبل القيمة الم ُرجعة من الدالة ثم اختبر قيمته إن كانت NULLأم لا.
إنطلاقا من ifالأول ،أعرف هل fgetsعملت على ما يرام أم حدث مشكل ما ) قام المستخدم
بادخال محارف أكبر من العدد المسموح به (.
إذا تم كل شيء بشكل جيد ،سأذهب للبحث عن الـ \nباستعمال الدالة strchrثم استبداله بالمحرف
\0كما في الشكل التالي.
262
استرجاع سلسلة محارف
هذا المخطط يبې ّن أن السلسلة ال ّتي تمت قراءتها من طرف الدالة fgetsهي ” ،” NEBRA\n\0ثم قمنا
باستبدال الـ \nبـ \0و هذا ما أعطانا ” .،” NEBRA\0\0
ليس مشكلا أن توجد علامتا \0متتابعتان .الحاسوب سيتوقف عند الإشارة الأولى و يعتبرها نهاية السلسلة.
و النتيجة ؟ حسنا ،لقد عملت بشكل جي ّد.
)][1 int main(int argc, char *argv
{2
;]3 char name[10
;)” ? 4 printf(”What’s your name
;)5 read(name, 10
;)6 printf(”Ah ! Your name is %s !\n\n”, name
;7 return 0
}8
What’s your name ? NEBRA
! Ah ! Your name is NEBRA
تفر يغ المتغيّر المؤق ّت
لم نصل بعد إلى نهاية الأمور المزعجة.
نحن لم نقم بتحليل الحالة التي يقوم فيها المستعمل بإدخال محارف أكثر من ما هو مسموح به !
What’s your name ? Jean Edouard Albert 1er
! Ah ! Your name is Jean Edou
بما أن الدالة fgetsتدعم الحماية ،فهي توقفت عند الحرف التاسع الذي قام المستعمل بإدخاله لأنّنا حجزنا
جدولا من 10محارف ) يجب عدم نسيان أ ّن العاشر محجوز لإشارة نهاية السلسلة ( .المشكل هو أن بقي ّة
السلسلة ال ّتي لم تتم قراءتها ”ard Albert 1er” .لم تختف ! و إن ّما لازالت موجودة في المتغير المؤق ّت .هذا المتغير
المؤقت هو مكان في الذاكرة يعمل كوسيط بين لوحة المفاتيح و الجدول ال ّذي سيتم تخزين السلسلة فيه .في الـ،C
لدينا مؤش ّر نحو المتغير المؤقت ،و هو stdinالذي تكلمنا عنه قبل قليل.
أعتقد أن مخططا صغيرا سيساعد على توضيح الأمور.
263
الفصل ب .10.إدخال ن ّص بشكل أكثر أمانا
حينما يقوم المستعمل بإدخال نص بلوحة المفاتيح ،فإن نظام التشغيل ) ويندوز مثلا ( يقوم بنسخ النص
مباشرة في المتغير المؤق ّت . stdin
مهمة الدالة fgetsهي إحضار المحارف الموجودة في المتغير المؤقت ووضعها في الذاكرة التي قمت أنت
بتحديدها ) الجدول .( string
بعد القيام بعملها ،تمسح ما قامت بنسخه من المتغير المؤق ّت.
إذا عمل كل شيء على ما يرام ،فالدالة fgetsستقوم بإفراغ كل محتوى المتغير المؤق ّت ،أي أن هذا
الأخير سيكون فارغا ً بعد استدعاء الدالة .لـكن في الحالة التي يقوم المستخدم بإدخال كثير من المحارف لا
يمكن أن يسعها المكان المحجوز لها ،فإنه يتم مسح الحروف التي تمت قراءتها فقط ،و بالتالي بعد استدعاء الدالة
fgetsفإن المتغير المؤق ّت يحتوي دائما المحارف المتب ّقية !
فلنجر ّب مع سلسلة كبيرة :
1 )][int main(int argc, char *argv
2
{
;]3 char name[10
;)” ? 4 printf(”What’s your name
;)5 read(name, 10
;)6 printf(”Ah ! Your name is %s !\n\n”, name
;7 return 0
}8
264
استرجاع سلسلة محارف
What’s your name ? Jean Edouard Albert 1er
! Ah ! Your name is Jean Edou
الدالة fgetsقامت بنسخ المحارف التسعة الأولى كما كان متوق ّعا .المشكل هو أن المحارف المتبقية لازالت
في المتغير المؤقت !
هذا يعني أنه لو استدعينا الدالة fgetsمرة أخرى فإنها ستقوم بقراءة ما كان متب ّقيا في المتغير المؤقت !
فلنجر ّب هذه الشفرة :
1 )][int main(int argc, char *argv
2
{
;]3 char name[10
;)” ? 4 printf(”What’s your name
;)5 read(name, 10
;)6 printf(”Ah ! Your name is %s !\n\n”, name
;)7 read(name, 10
;)8 printf(”Ah ! Your name is %s !\n\n”, name
;9 return 0
} 10
نحن نقوم باستدعاء الدالة readم ّرتين لـكنك ستلاحظ أن ّه لن يتم السماح لك بإدخال اسمك مرتين،
وذلك لأن الدالة fgetsلن تطلب من المستخدم إدخال أ ّي ن ّص في المر ّة الثانية لأ ّنها ستجده في المتغير
المؤقت !
265
الفصل ب .10.إدخال ن ّص بشكل أكثر أمانا
What’s your name ? Jean Edouard Albert 1er
! Ah ! Your name is Jean Edou
! Ah ! Your name is ard Alber
إذا قام المستعمل بإدخال محارف كثيرة ،فإن الدالة fgetsستحمي البرنامج من مشكل تجاوز الذاكرة،
لـكن يبقى دائما آثار الن ّص في المتغير المؤقت .لذا يجب تفر يغ هذا الأخير.
سنقوم إذا بتحسين عمل الدالة ، readو سنقوم في الحالات التي ٺتطلب ذلك باستدعاء دالة نسميها
، clearBufferلـكي نتأكد من تفر يغ المتغير المؤقت في حال ما احتوى على محارف زائدة :
)(1 void clearBuffer
{2
;3 int c = 0
)4 while (c != ’\n’ && c != EOF
{5
;)(6 c = getchar
}7
}8
9 )int read(char *string, int length
10
{
11 ;char *inputPosition = NULL
12
)if (fgets(string, length, stdin) != NULL
{ 13
;)’14 inputPosition = strchr(string, ’\n
)15 if (inputPosition != NULL
{ 16
17 ;’*inputPosition = ’\0
18
}
19 else
{ 20
;)(21 clearBuffer
} 22
;23 return 1
} 24
25 else
{ 26
;)(27 clearBuffer
;28 return 0
} 29
} 30
الدالة readتستدعي الدالة clearBufferفي حالتين :
• السلسلة المدخلة طو يلة جدا ً ) يمكننا أن نعرف ذلك بعدم وجود الإشارة \0في السلسلة المنسوخة (
• إذا حدث أي خطأ مهما كان ،يجب تفر يغ محتوى المتغير المؤقت لأسباب حماية لـكي لا يبقى شيء هناك.
266
تحو يل سلسلة محرفي ّة إلى عدد
الدالة clearBufferقصيرة لـكنها عميقة .فهي تقرأ المتغير المؤقت محرفا ًمحرفا ًباستعمال الدالة . getchar
هذه الدالة تقوم بإرجاع ) intو ليس ، charسوف تعرف السبب لاحقا ،أيّا يكن (.
سنكتفي نحن باسترجاع القيمة في متغير cمن نوع . intنقوم بحلقة تكرار ية مادمنا لم نقرأ بعد المحرف \0
أو الرمز ) EOFنهاية الملف ( و هما يعنيان :لقد وصلت إلى نهاية المتغير المؤقت .سنتوق ّف عند الوصول إلى
أحد هذين المحرفين.
يبدو عمل الدالة clearBufferصعبا ً قليلا ً لـكنها تقوم بعملها .لا تتردد في تكرار قراءة الشرح عدة
مرات من أجل الفهم الجيد.
ب 3.10.تحو يل سلسلة محرفي ّة إلى عدد
دالتنا readهي فعالة و قو ي ّة الآن ،لـكنها تجيد قراءة النصوص فقط .ستتساءل حتما ” :لـكن كيف
نقوم باسترجاع عدد ؟”
الحقيقة أن الدالة fgetsهي دالة مبدئية .مع fgetsلا يمكن قراءة سوى النصوص ،و لـكن توجد
دوال أخرى تقوم بتحو يل النص إلى عدد.
: strtolتحو يل سلسلة محرفي ّة إلى long
نموذج هذه الدالة خاص نوعا ًما :
;) 1 long strtol( const char *start, char **end, int base
الدالة ستقوم بقراءة السلسلة المحرفي ّة المرسلة إليها ) ( startو ستحاول تحو يلها إلى longباستعمال
الأساس ) ( baseالمحدد ) غالبا ً ما نستعمل الأساس ،10لأننا نستعمل الأرقام من 0إلى ،9و لهذا ضع
مكانه العدد .( 10ستقوم بإرجاع العدد الذي نجحت في قراءته.
بالنسبة لمؤشر المؤشر ، endفالدالة ستقوم استغلاله لإرجاع أول محرف صادفته و لم يكن رقما ً .لـكننا لسنا
بحاجة إليه ،فلنكتفي بوضع NULLمكانه لنقول أننا لا نريد استرجاعه.
على السلسلة المحرفي ّة أن تبدأ برقم ،فبعد العدد كل شيء يتم تجاهله .يمكن أن تكون مسبوقة بفراغات.
هذه أمثلة للفهم الجيد :
;1 long i
2 i = strtol( ”148”, NULL, 10 ); // i = 148
3 i = strtol( ”148.215”, NULL, 10 ); // i = 148
4 i = strtol( ” 148.215”, NULL, 10 ); // i = 148
5 i = strtol( ” 148+34”, NULL, 10 ); // i = 148
6 i = strtol( ” 148 dead leaves”, NULL, 10 ); // i = 148
( 7 i = strtol( ” There are 148 dead leaves”, NULL, 10 ); // i = 0
)error : The string ’doesnt start with a number
267
الفصل ب .10.إدخال ن ّص بشكل أكثر أمانا
كل السلاسل التي تبدأ برقم ) أو ربما بفراغات قبله ( سيتم تحو يلها إلى longحتى الوصول إلى محرف
غير مقبول ) نقطة ،فاصلة ،علامة استفهام ،زائد ،الخ (.
بالنسبة لسلسلة لا تبدأ بأرقام و أو بفراغات تليها أرقام ،فلا يمكن تحو يلها و بالتالي تقوم الدالة بإرجاع
القيمة .0
يمكننا كتابة الدالة ، readLongو التي تقوم باستدعاء الدالة ) readلقراءة النص ( ،و بعد ذلك تحو يل
النص إلى عدد :
)(1 long readLong
{2
3 char textNumber[100] = {0}; // 100 boxes are sufficient
))4 if (read(textNumber, 100
{5
6 // If we read the text without problems, we convert
7 } textNumber to long and we return it
8 else ;)return strtol(textNumber, NULL, 10
9 {
10 // If ’theres a problem, we return 0
11 } ;return 0
12
13
} 14
يمكنك تجريب الشفرة داخل mainبسيط.
)][1 int main(int argc, char *argv
{2
;3 long age = 0
;)” ? 4 printf(”How old are you
;)(5 age = readLong
;)6 printf(”Ah ! You are %d years old !\n\n”, age
;7 return 0
}8
How old are you ? 18
!Ah ! You are 18 years old
strtodتحو يل سلسلة محرفي ّة إلى double
الدالة strtodمطابقة للدالة ، strtolالفرق الوحيد هو أنها ستحاول قراءة عدد عشر ّي و إرجاع
. double
;) 1 double strtod( const char *start, char **end
268
مل ّخص
تجد أن المعامل الثالث baseاختفى هنا ،بينما يبقى مؤش ّر المؤش ّر endال ّذي لا يفيدنا في شيء.
على خلاف الدالة السابقة ،فإن هذه الدالة ستأخذ في الحسبان ”النقطة” العشر ية .عندما أقول نقطة يعني
أن الدالة لا تقبل الفاصلة ” ) ”,يبدو أ ّنها مبرمجة من طرف ناطقين بالإنجليز ية (.
فلتقم بكتابة الدالة readDoubleبنفسك .إن كتابتها مماثلة للدالة ، readLongالاختلاف الوحيد هو
أنها ستستدعي الدالة strtodثم ستقوم بإرجاع قيمة . double
يعني أنك ستكتب التالي في الـكونسول :
What’s your weight ? 67.4
! Ah ! Your weight is 67.400000 kg
حاول بعد ذلك تعديل الدالة readDoubleلتقبل الفاصلة أيضا ً كفاصل عشري .إن الأمر بسيط :
فقط قم باستبدال كل تكرار للمحرف ” ” ,بالمحرف ” ) ” .بالاستعانة بالدالة ،( strchrثم قم ببعث
النص الجديد إلى الدالة . strtod
مل ّخص
• الدالة scanfبالرغم من أنها تبدو سهلة و طبيعية إلا انها مع ّقدة و تفرض علينا بعض الحدود .فمثلا ً،
هي لا تقبل قراءة نص يحتوي فراغات.
• نقول أننا تسببنا في الـ buffer overflowإذا تجاوزنا المساحة المخصصة في الذاكرة ،فمثلا ً لو قام المستخدم
بإدخال 10محارف و نحن قد حجزنا 5خانات فقط.
• الحل الأمثل هو استدعاء الدالة fgetsلتقوم باسترجاع النص الذي ي ُدخله المستعمل.
• يجب أن تتجنب استعمال الدالة getsبأي ثمن لأ ّنها لا تحمي من الـ.buffer overflow
• يمكنك كتابة دالة خاصة بك ،تقوم باستدعاء الدالة fgetsكما فعلنا لـكيّ تح ّسن عملها.
269
الفصل ب .10.إدخال ن ّص بشكل أكثر أمانا
270
الجزء ج
إنشاء ألعاب 2Dفي SDL
271
الفصل ج1.
ٺثبيت الـSDL
ابتداءا ً من الآن ،إنتهت الدروس النظر ية ! لأننا سنمر ّ إلى مرحلة مهمّة ،و سنستمتع بالتطبيق بالإستعانة
بمكتبة نسميها .SDL
في الدروس السابقة كنا قد تطر ّقنا تقريبا ً لك ّل أساسيات اللغة ،Cلـكن تبقى هناك دائما ً بعض التفاصيل
الصعبة نوعا ًما لنكتشفها .سأقول لك بأنه يمُكن لهذا الكتاب أن يتوق ّف هنا مخـبرا إيّاك ” :نعم لقد تعل ّمت البرمجة
بلغة ،”Cلـكني متأكّد بأن الجميع سيشاركني الرأي لو قلت بأن الم ُبرمج سيح ّس نفسه دائما ًمبتدئا ًمادام لم ”يخرج”
من الـكونسول !
الـ SDLهي مكتبة ت ُستخدم خا ّصة لإنشاء ألعاب ثنائية الأبعاد .سنتعر ّف في هذا الدرس على هذه المكتبة
و نتعلّم كيف نقوم بتثبيتها.
نسمي هذا النوع من المكتبات بمكتبات الطرف الثالث ) .(third party librariesيجب أن تعرف أنه هناك
نوعين من المكتبات :
• المكتبة القياسية ) : (standard libraryو هي المكتبة القاعدية التي تعمل على ك ّل أنظمة التشغيل )من
هنا تم استنباط الكلمة (standardو هي تسمح بالقيام بأمور بسيطة كـ . printfهذه المكتبات يتم ّ
تسطيبها تلقائيّا عند ٺثبيتك للبيئة التطوير ية و المترجم.
خلال الجزئين الأ ّولين من هذا الكتاب ،كنا ّقد استعملنا المكتبة القياسي ّة فقط ) ، stdio.h ، stdlib.h
.(… time.h ، string.hلم نقم بدراستها بالتفصيل لكن ّا جرّبنا منها جزءا ً كبيرا ً .إن كنت تريد
معرفة المزيد عن هذا النوع من المكتبات أ ْجرِ بحثا ً في ،Googleمثلا ً بكتابة ” ،”C standard libraryو
ستجد نماذج الدوال في هذه المكتبة ،بالإضافة إلى شرح قصير حول دور ك ّل دالة.
• مكتبات الطرف الثالث ) :(third party librariesهي مكتبات لا يتم ٺثبيتها تلقائيا .و إن ّما يجب عليك
تنز يلها من الأنترنت و ٺثبيتها بنفسك على حاسوبك.
273
الفصل ج .1.ٺثبيت الـSDL
على عكس المكتبات القياسية ،التي تكون بسيطة نسبي ّا و تحتوي على عدد قليل من الدوال ،فإنه توجد
الآلاف من مكتبات الطرف الثالث ،و التي تمت كتابتها من طرف مبرمجـين آخرين .بعضها جي ّدة ،و
أخرى أقل ،بعضها مدفوع ،و بعضها الآخر مجاني ،إلخ .الأمر المثالي هو إيجاد مكتبة جي ّدة و مجانية في
نفس الوقت !
إنه لمن المستحيل أن أضع لك درسا ًيشرح كل المكتبات الموجودة .حت ّى لو أمضيت حياتي كل ّها 24ساعة
،24 /لن أستطيع !
لذا سأق ّدم لك مكتبة واحدة فقط مكتوبة بالـ Cو مُستعملة من طرف مبرمجـين مثلك.
هذه المكتبة تدعى .SDLالسؤال المطروح هو لماذا اخترت هذه المكتبة بالضبط ؟ ما الذي يميّزها عن باقي
المكتبات ؟
هذه أسئلة سأبدأ في الإجابة عليها إنطلاقا ًمن الآن.
ج 1.1.لماذا نختار الـ SDL؟
اختيار مكتبة ليس بالأمر السهل !
كما قلت لك الآن ،توجد الآلاف من المكتبات للتنز يل.
بعضها بسيط ،و بعضها كبير جدا ً لدرجة أن درسا ًكهذا لا يكفي أن يشرحها كل ّها !
الاختيار صعب .لـكن ّي اخترت هذه المكتبة ،التي هي نوعا ًما سهلة الاستعمال ،كبداية .ستكون هذه إذا
أ ّول مكتبة تقوم باستعمالها )إذا لم نحسب المكتبة القياسية(.
إنه من الواضح أن أغلب القر ّاء يريدون معرفة كيفية فتح نوافذ ،إنشاء لعبة ،إلخ .و لـكن إن كنت تحب
الـكونسول فيمكننا الاستمرار فيها لوقت أطول ،إذا أردت ،لا ؟ إذا لدينا هنا بعض الفضول !
أودّ كثيرا ً أن أر يك كيف تعمل ك ّل هذه الأمور ،لـكننا سنحاول أن نتطر ّق إليها خطوة بخطوة ،و بالنسبة
للأعمال التطبيقية ،فلدينا عملان تطبيقيان لهذا الجزء من الكتاب !
لقد اخترت لك مكتبة سهلة و قو ية ،ستكون كبداية لك في تحقيق )تقريبا( أحلامك المتعل ّقة بالواجهة
الرسومية ،و من دون تعب )حسنا ً ،ك ّل شيء نسبيّ بالطبع !(.
الـ ،SDLاختيار جي ّد !
سنقوم الآن بدراسة هذه المكتبة .لماذا اخترتها هي و ليس أخرى ؟
274
لماذا نختار الـ SDL؟
• هي مكتبة مكتوبة بلغة : Cأي أنه بإمكان المبرمجـين أن يستعملوها في برامجهم المكتوبة بالـ .Cو كما هو
الحال بالنسبة لأغلب المكتبات المكتوبة بالـ ،Cيمكن استعمالها في لغة الـ C++بالإضافة إلى لغات برمجية
أخرى.
• هي مكتبة حُرّة و مجانية :و هذا كي لا تضطر ّ لدفع أي ثمن مقابل استعمالك ما سأق ّدمه لك في بقي ّة
الكتاب .على عكس ما قد نعتقد ،إيجاد مكتبة جيدة و مجانية ليس أمرا ً صعبا ًكثيرا ً ،فقد انتشرت كثيرا ً
في أيامنا هذه .المكتبة الحرة هي ببساطة مكتبة يمكنك الحصول على الشفرة المصدر ية الخاصة بها .في
حالتنا هذه ،رؤ ية الشفرة ليس مُهمّا بالنسبة لنا .لـكن كونها حرة يفتح لنا الباب من أجل ميزات أخرى
أهم ّها المداومة )أي أنه إن توقف صاحب المكتبة عن تطويرها ،يمُكن لمبرمجـين آخرين أن يكملوا عمله(،
بالإضافة إلى مج ّاني ّتها غالبا .هذا يعني عدم إمكانيّة اختفاء المكتبة في يوم من الأيام.
• ي ُمكنك إنشاء برامج تجار ية ذات ملـكية خاصة بفضل هذه المكتبة .قد أكون قد تسرّعت بهذا الكلام،
لـكن ّه يجب اختيار مكتبة حرّة تمنحك الحر ي ّة الأقصى .الحقيقة أنه يوجد نوعان من المكتبات الح ُرة :
– المكتبات تحت رخصة : GPLمكتبات مجانية ،و يمكنك رؤ ية الشفرة المصدر ية الخاصة بها ،لـكن
بشرط أن تقوم أنت كذلك بنشر الشفرة المصدر ية الخاصة بالبرنامج الذي أنشأته باستخدامها.
– المكتبات تحت رخصة : LGPLمثل سابقتها ،لـكن ليس عليك أن تنشر الشفرة المصدر ية الخاصة
بالبرنامج .أي أنه يمكنك بها إنشاء برامج مملوكة.
بالرغم من أنه يمكنك قانونيّا عدم نشر الشفرة المصدر ية الخاصة بالبرنامج ،إلا أنني أنصحك بذلك.
فبهذا يمكنك أن تأخذ رأي المبرمجـين الأكثر تمر ّسا ً منك .و هذا يسمح لك بالتح ّسن .بعد هذا،
فإن إنشاء برنامج حُر أو ذو ملـكية خاصة ،يرجع لطبيعة تفكير كل شخص .لن أدخل في نقاش
بخصوص هذا الموضوع ،لـكن فلتعلم أن ك ّل النوعين له مميزاته و مساوئه.
• هي مكتبة متعددة المن ّصات ) : (multi-platformسواء كنت على الويندوز ،الماك أو اللينكس ،ستعمل
لديك هذه المكتبة .و الحقيقة أن هذه نقطة قوّة يراها المبرمجون بالمكتبة :يمكنها أن تعمل على عدد كبير
جدا ً من أنظمة التشغيل ،فعلى غرار الويندوز و الينكس و الماك ،هي تشتغل أيضا ًعلى ،Amiga ،Atari
… Dreamcast ،Symbianإلخ .أي أنه بالإمكان لبرامجك أن تعمل حتى على أجهزة Atariالقديمة ! مع
ذلك يجب القيام ببعض التعديلات و رب ّما استخدام مترجم خاص .لن أدخل في التفاصيل هنا.
275
الفصل ج .1.ٺثبيت الـSDL
• أخيرا ،فإن هذه المكتبة تسمح لك بالقيام بالـكثير من الأمور الممتعة التي سنتعر ّف إليها من خلال الدروس
القادمة .لا أقول أ ّن مكتبة ر ياضي ّاتيّة قادرة على ح ّل معادلات من الدرجة الرابعة ليست ممتعة ،لـكن ّي
سأركّز على أن يكون هذا الدرس سهلا قدر الإمكان لـكيّ يحث ّك على البرمجة.
هذه المكتبة ليست مخصصة فقط لإنشاء ألعاب الفيديو .سأعترف بأن معظم البرامج التي تمت كتابتها بهذه
المكتبة ،هي عبارة عن ألعاب ،لـكن هذا لا يعني أنك مجـبر لاستعمالها من أجل ذلك .فكما نعلم ،ك ّل شيء
ممكن بالعمل و الاجتهاد .كنت قد رأيت من قبل محرر نصوص تمت برمجته بالـ ،SDLغلى الرغم من أن ّه هناك
مكتبات أخرى أحسن لهذا الغرض .إن كنت تريد برمجة واجهة رسومية تقليدي ّة تسمح بإظهار نافذة ،زر،
قائمة ،إلخ .فأنا أنصحك إذا بالتوجّه إلى المكتبة .GTK+
الإمكانية المتاحة بالـSDL
المكتبة SDLهي مكتبة منخفضة المستوى .هل ٺتذكر أول الدروس حينما تكلّمت لك عن لغات البرمجة عالية
المستوى و لغات البرمجة منخفضة المستوى ؟ هذا ينطبق على المكتبات أيضا ً.
• المكتبات منخفضة المستوى :تحتوي على دوال قاعدية ج ّدا .يوجد عدد قليل من هذه الدوال لأن ّه
يمكننا القيام بك ّل شيء بها .و هذه الدوال لبساطتها تكون سر يعة ج ّدا .لهذا فالبرامج المنشأة بهذا النوع
من المكتبات تكون عادة الأسرع.
• المكتبات عالية المستوى :تحتوي على الـكثير من الدوال التي تسمح بالقيام بالـكثير من المهام .هذا يجعلها
أبسط من ناحية الاستخدام.
لـكن هذا النوع من المكتبات يكون عادة ”كبيرا” ،و ليس من السهل دراستها و معرفتها بأكملها .كما أنها
قد تكون أثقل من المكتبات منخفضة المستوى )لـك ّن هذا قد لا يكون واضحا(.
على العموم ،لا يمكننا القول بأن ”مكتبة منخفضة المستوى هي أحسن من مكتبة عالية المستوى” أو العكس.
فك ّل منهما لها مميزات و مساوئ .الـ SDLالتي سنقوم بدراستها ،تنتمي إلى المكتبات منخفضة المستوى.
يجب إذا أن ٺتذكر بأن الـ SDLتق ّدم دوالا قاعدية .يمكنك إذا الرسم بيكسلا ببيكسل ،رسم مستطيل أو
إظهار صور .هذا ك ّل شيء ،و ص ّدقني أ ّن هذا كا ٍف.
• بتحر يك صورة ،يمكنك أن تقوم بتحر يك شخصي ّة.
• بإظهار العديد من الصور الواحدة تلو الأخرى بسرعة ،يمكنك إنشاء تحر يك ).(animation
• بوضع العديد من الصور ،الواحدة بجنب الأخرى ،يكون باستطاعتك إنشاء لعبة حقيقي ّة.
276
لماذا نختار الـ SDL؟
كمثال عن لعبة تم صنعها بالـ ،SDLاعلم أ ّن اللعبة الشهيرة ” ،”Civilisation : Call to powerتم دعمها في
نظام اللينكس لاحقا ًباستخدام الـ.SDL
يجب أن تعلم أ ّن جودة اللعبة تعود إليك و إلى الفر يق الذي تعمل معه .إن كان لديك مصمم موهوب،
فيمكنك صنع لعبة أجمل.
الشيء الوحيد الذي يح ّد الـ SDLهو أنها تقتصر على الألعاب ثنائية الأبعاد ،و لم ت ُنشأ من أجل الألعاب
ثلاثية الأبعاد .هذه أمثلة على ألعاب يمكن تحقيقها بالـ) SDLليست سوى قائمة صغيرة ،ك ّل شيء ممكن مادام
ثنائيّ الأبعاد( :
• Breakout
• Bomberman
• Tetris
• ألعاب المن ّصات … ،Rayman ،Sonic ،Super Mario Bros :
• RPGثنائية الأبعاد ،Zelda :الأجزاء الأولى للعبة ،Final Fantasyإلخ.
لا يمكن وضع لائحة كاملة ،الأمر يعود فقط للقدرة على التخي ّل .و ص ّدقني بأنك قادر على برمجة ألعاب فائقة
الروعة .فلقد رأيت أحد القر ّاء ينشئ تهجينا بين Breakoutو .Tetris
فلنعد إلى الأرض و لنمسك خيط هذا الدرس .سنقوم الآن بتسطيب المكتبة ،لنتم ّكن من التق ّدم في العمل.
277
الفصل ج .1.ٺثبيت الـSDL
ج 2.1.تنز يل الـSDL
الموقع الرسمي للمكتبة SDLسيصبح قريبا الوجهة ال ّتي نقصدها كثيرا .هناك ،يوجد ك ّل ما تحتاجه ،بدء ً من
المكتبة نفسها و مرورا إلى التوثيق ) (Documentationالخاص بها.
http://www.libsdl.org/
إذهب إلى اللائحة Downloadالمتواجدة على يسار الصفحة الرئيسية للموقع.
اختر النسخة الأحدث ال ّتي تجدها ) SDL 1.2عندما كتبت هذه السطور(.
صفحة التنز يل مجز ّأة إلى عدة أجزاء.
• الشفرة المصدر ية ) : (Source codeهنا يمكنك تحميل الشفرة المصدر ية الخاصة بالمكتبة .أدري أن
القراء فضوليون ليعرفوا كيف تعمل المكتبة من الداخل ،لـك ّن هذا لن يفيدنا .الأسوأ هو أن ّه سيقوم
بإلهائك عن هدفنا الرئيسي.
• مكتبات وقت التشغيل ) : (Runtime librariesهي الملفات التي تحتاج إلى تقديمها مع الملف التنفيذي
حين تريد أن تعطي برنامجك لشخص آخر .بالنسبة للويندوز ،أنا أتكلم عن الملف . SDL.dllهذا
الأخير يجدر به أن يتواجد إما :
– بنفس المجل ّد الذي يحتوي الملف التنفيذي )أنا أنصحك بهذا( .الأحسن دائما هو أن تعطي الـDLL
مع الملف التنفيذي و تبقيهم في نفس المجلد .إذا وضعت الـ DLLفي المجل ّد الخاص بالويندوز ،لن
يكون عليك إلحاق الـ DLLمع ك ّل مجل ّد يحتوي البرنامج .SDLو مع ذلك قد تحدث بعض المشاكل
في حال ما قمت بمسح نسخة أحدث من الـ.DLL
– في المجل ّد . C:\Windows
• مكتبات التطوير ) : (Development librariesهي الملفات ) .aأو .libبالنسبة للـ (Visualو
الملفات .hالتي تسمح بإنشاء برامجك .SDLهذه الملفات ليست مفيدة إلا بالنسبة إليك أنت فقط
المبرمج .أي أنه ليس عليك تقديمها مع ملفات البرنامج حين تنتهي من هذا الأخير.
إذا كنت تعمل في الويندوز ،فسأعطيك ثلاثة نسخ ،و ذلك حسب المترجم الخاص بك :
• : VC6بالنسبة للذين يستخدمون النسخ القديمة غير المجانية من ) Visual studioلا أعتقد أن هناك من
القر ّاء من لازال يستعمل هذه النسخ( .ستجد فيها على أي حال الملفات . .lib
• : VC8بالنسبة للذين يستعملون Visual Studio 2005 Expressأو نسخة أحدث ،ستجد فيها الملفات
. .lib
• : mingw32بالنسبة للذين يستعملون ) Code::Blocksستجدون فيها إذا الملفات .( .a
278
إنشاء مشروع Windows : SDL
الشيء الخاص هنا ،هو أن ”مكتبات التطوير” تحتوي كل الملفات .hو الملفات ) .aأو ( .lib
بالطبع ،لـكنها تحتوي أيضا ًالملف SDL.dllو ملفات التوثيق الخاصة بالـ! SDL
باختصار ،ك ّل ما عليك تحميله هو ”مكتبات التطوير” ،فك ّل ما تحتاجه يتواجد بداخلها.
لا تخطئ في الرابط ! قم باختيار الـ SDLفي قسم ” ”Development librariesو ليس من قسم ”Source
! ”code
ماذا هو التوثيق ) (Documentation؟
التوثيق هو قائمة تحوي اللائحة الكاملة للدوال الخاصة بمكتبة معي ّنة .و كل هذه الملفات تكون مكتوبة
بالانجليز ية )حتى لو كان كاتبوها مبرمجـين فرنسيين( .هذا سبب آخر يدفعك للتق ّدم في لغة ! Shakespeare
محتوى ملفات التوثيق ليس عبارة عن درس ،بل هي عادة موجزة .الشيء الإيجابي بالنسبة لدرس ،هي
أ ّنها تحتوي قائمة لكل الدوال الموجودة ،فهي إذا المرجع للمبرمج.
في كثير من الأحيان ستجد مكتبات بدون دروس تشرح كيفية عملها .و هنا لا يبقى لك سوى التوثيق ال ّذي
نسميه عادة ” ،”docو يجب عليك تدبّر أمرك بهذا فقط )حت ّى لو كان هذا صعبا أحيانا عندما تبدأ من دون أي ّة
مساعدة( .المبرمج الحقيق ّي هو من يتم ّكن من إيجاد ضال ّته في الـ”.”doc
لح ّد الآن ،أنت لست بحاجة إلى التوثيق الخاص بالـ SDLلأنني أنا من سيشرح لك كيفية عملها .لـكن بما
أنني غير قادر على أن أشرح لك كل الدوال التي بها ،ستحتاج إلى قراءة التوثيق لاحقا.
مل ّفات التوثيق توجد أصلا ًفي الحزمة ” ”Development librariesكما سبق و ذكرت ،لـكن بإمكانك تحميلها
وحدها من القائمة . Downloadable / Documentation
أنصحك أن تجمع ملفات HTMLالخاصة بالتوثيق في مجل ّد خا ّص )اسمه مثلا ً ( Doc SDLثم انشاء اختصار
إلى الفهرس . index.htmlو الهدف من هذا هو الوصول إلى هذه الملفات بشكل أسرع حينما تحتاج إليها.
ج 3.1.إنشاء مشروع Windows : SDL
ٺثبيت مكتبة قد يكون أكثر صعوبة قليلا ًعلى ما تعوّد عليه الجميع .هنا لا يوجد ٺثبيت تلقائيّ يطلب منك أن
تنقر ”التالي”” ،التالي”” ،التالي”” ،إنتهى”.
الحقيقة أن ٺثبيت مكتبة أمر صعب على المبتدئين .لـكن لأقوم برفع المعنو يات فإن تسطيب مكتبة SDL
أمر سهل جدا ً مقارنة بتسطيب مكتبات أخرى أتيحت ليّ فرصة استخدامها من قبل )هناك من يتم إعطاؤك منها
الشفرة المصدر ية فقط ،بينما انت ٺتولى أمر الترجمة !(.
و الحقيقة أن كلمة ”ٺثبيت” ليست الملائمة هنا .لن نقوم بتثبيت أي شيء ،فقط نريد أن نصل إلى الـكيفية
التي ننشئ فيها مشروع SDLفي البيئة التطوير ية الخاصة بنا.
279
الفصل ج .1.ٺثبيت الـSDL
ستختلف كيفية التعامل حسب البيئة التطوير ية التي تستعملها .سأقوم بتقديم الطر يقة الخاصة بك ّل بيئة من
بيئات التطوير التي ق ّدتمها في بداية الكتاب ،و هكذا كي يستطيع الجميع المتابعة.
سأعرض الآن كيف ننشئ مشروع SDLفي ك ّل واحد من البيئات الثلاث السابقة.
تسطيب الـ SDLفي Code::Blocks
استخراج ملفات الـSDL
افتح الملف المضغوط ” ”Development Librariesالذي قمت بتنز يله.
هذا الملف هو بامتداد .zipبالنسبة للـ Visualو .tar.gzبالنسبة للـ ) mingw32يلزمك برنامج مثل
Winrarاو 7-Zipلـكي تقوم بفك الضغط عن الملفات ذات الصيغة .( .tar.gz
الملف المضغوط يحتوي العديد من المجل ّدات الداخلية ،و هذه هي الملفات التي تهمّنا :
• : binيحتوي الملف .dllالخاص بالـ.SDL
• : docsيحتوي الملفات التوثيقي ّة الخاصة بالـ.SDL
• : includeيحتوي الملفات الرأسية .(headers) .h
• : libيحتوي الملفات ) .libأو .aبالنسبة لـ(Code::Blocks
يجب عليك استخراج كل الملفات و المجل ّدات الداخلية ووضعها في مكان ما بالقرص الصلب لحاسوبك،
يمكنك مثلا وضعها في مجلد خاص بـ SDLداخل مجل ّد الـ.Code::Blocks
280
إنشاء مشروع Windows : SDL
بالنسبة لي فإن المسار هو التالي :
C:\Program Files (x86)\CodeBlocks\SDL-1.2.13
احفظ المسار الذي به البرنامج ،ستحتاج إليه عندما تريد تعديل إعدادات Code::Blocksلاحقا.
و الآن ،علينا بالقيام بخطوة بسيطة ،لتسهيل الأمور علينا ،توجّه إلى المسار ) include/SDLفي حالتي،
هو متواجد بـ ،( C:\Program Files (x86)\CodeBlocks\SDL-1.2.13\include\SDLقم
بنسخ الملفات الرأسية .hفي المجل ّد الأب) ،أي في :
.( C:\Program Files (x86)\CodeBlocks\SDL-1.2.13\include
ها قد تم تسطيب المكتبة ،فلنقم الآن بتعديل إعدادات .Code::Blocks
إنشاء مشروع SDL
افتح Code::Blocksو قم بانشاء مشروع جديد.
281
الفصل ج .1.ٺثبيت الـSDL
عوض أن تقوم باختيار Console Applicationكما جرت العادة ،اختر .SDL project
النافذة الأولى لا جدوى منها ،قم بتجاوزها بالضغط على ”التالي”
).(Next
282
إنشاء مشروع Windows : SDL
سي ُطلب منك أن تقوم بإدخال اسم المشروع ،قم بذلك كالعادة :
الآن يجب اختيار المسار الذي ثبتنا فيه المكتبة :
283
الفصل ج .1.ٺثبيت الـSDL
إظغط على الزر الذي يأخذ شكل مرب ّع به ثلاث نقاط ،ستظهر لك النافذة التالية :
284
إنشاء مشروع Windows : SDL
قم باختيار المسار )بالنسبة لي هو .( C:\Program Files (x86)\CodeBlocks\SDL-1.2.13
قد تظهر لك في مكان النافذة السابقة هذه النافذة :
إملأ الحقل
بنفس الطر يقة السابقة ،ثم ّ اضغط على زر الخروج ،و ستلاحظ أن المسار قد تم تسجيله كالتالي :
285
الفصل ج .1.ٺثبيت الـSDL
إضغط على ،Nextستظهر لك نافذة اختيار المترجم ،قم باختيار الأوضاع Realeaseأو ) Debugهذا لا
يهم(.
أخيرا إضغط على ”إنهاء” ) .(Finishسيتم إنشاء المشروع التجريبي :
يحتوي المشروع على ملفين main.cppو ملف .bmpقبل أن تحاول القيام بالترجمة .يجب القيام بخطوة
أخيرة )عليك القيام بها دائما( ،و هي نسخ الملف SDL.dllمن ملفات المكتبة )ال ّذي يفترض أن يكون في
المسار ( C:\Program Files (x86)\CodeBlocks\SDL-1.2.13\bin\SDL.dllو ضعه في
المجل ّد الخاص بالمشروع.
286
إنشاء مشروع Windows : SDL
أخرج من Code::Blocksو أعد الدخول إليه ،ثم قم بترجمة البرنامج الم ُقترح مسبقا ً .يفترض أن تظهر النافذة
287
الفصل ج .1.ٺثبيت الـSDL
التالية :
إذا ظهرت لك النافذة السابقة ،فهنيئا لك ،المكتبة مثبتة بشكل جيد !
إن ظهرت لك الرسالة ” ”The application can’t start because the file SDL.dll is missingأي أنه
لا يمكن تشغيل البرنامج ،لأن ملف SDL.dllغير موجود ،فهذا يعني أنك لم تقم بنسخ الملف الأخير
في ملفات المشروع كما طلبت منك !
و كما قلت ،إن كنت تريد تسليم المشروع إلى أصدقائك ،عليك بارفاق الملف التنفيذي .exeبالملف
، SDL.dllبينما أنت لست بحاجة إلى إعطائهم الملفات .hو .aال ّتي لا تهم أحدا سواكم.
ملاحظات مترجمة الكتاب 1
إن لم يشتغل البرنامج و لازال المترجم يشير دائما إلى عدم وجود الملف ، SDL.dllفجرب نسخ هذا الأخير و
لصقه في المجلدين Debugو Releaseمن مجل ّد المشروع ،أي في نفس المكان الذي يتواجد به الملف التنفيذي.
أريد أن أنوّهك بأن المشروع الذي تم انشاؤه هو خاص باللغة ) C++لأنها اللغة التي يتم اختيارها تلقائيا من
بيئة التطوير ،كون أن هذه الأخيرة تم تطويرها للعمل بلغة الـ ،(C++سنقوم إذا بتحو يل هذا المشروع من C++
1ك ّل النص التالي و لقطات الشاشة المرافقة ابتداء ً من هنا و إلى نهاية هذا القسم ،يشرح الطر يقة ال ّتي استخدمتها مترجمة الكتاب
لتشغيل البرنامج في حالة ما لم تعمل الطر يقة السابقة )الأصلي ّة( .هذا يعني أ ّن هذه الفقرات التالية ليست موجودة في الكتاب الفرنسي
الأصلي ،و إن ّما هو مساهمة شخصي ّة من المترجمة.
288
إنشاء مشروع Windows : SDL
إلى Cببساطة.
توجّه إلى ملفات المشروع ،ستجد الملف main.cppقم بتغيير امتداده إلى . main.c
أدخل الآن إلى ،Code::Blocksستظهر لك على الأرجح النافذة التالية :
إظغط على الزر ”لا” ).(No
توجه إلى القائمة اليسار ية ،و قم بالنقر باليمين على الملف main.cppو اختر حذفه من المشروع :
289
الفصل ج .1.ٺثبيت الـSDL
اضغط على اسم المشروع ،و اطلب إضافة ملف جديد :
290
إنشاء مشروع Windows : SDL
اختر الملف main.cمن ملفات المشروع :
ستظهر لك نافذة أخرى ،قم باختيار ،Nextثم انقر على ”موافق” ).(OK
291
الفصل ج .1.ٺثبيت الـSDL
أنقر باليمين مجددا على الملف main.cو اختر ”خصائص” ): (Properties
توجه إلى القائمة ،Advancedستجد ،Compiler variableغي ّرها من CPPإلى CCكالتالي :
292
Windows : SDL إنشاء مشروع
: هذا ما سيبدو عليه المشروع الجديدOK إضغط بعد ذلك على
: ضع الشفرة التالية بدل الشفرة السابقة
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <SDL/SDL.h>
4 int main(int argc, char *argv[])
5{
6 SDL_Init(SDL_INIT_VIDEO);
7 SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE);
8 return EXIT_SUCCESS;
9}
293
الفصل ج .1.ٺثبيت الـSDL
و أخيرا ً ،من القائمة العلو ية ،اختر هدف البناء . Release
يمكنك ترجمة البرنامج ،ستظهر لك نافذة و تختفي فجأة ،لا تقلق ،سنعالج ذلك لاحقا ً ،أنا أهن ّئك ،كل شيء
يعمل بشكل جيد جدا.
يمكنك مسح الملف .bmpلأننا لسنا بحاجة إليه .بالنسبة للملف ، main.cيمكنك الآن استبدال محتواه
بالشفرة التالية :
>1 #include <stdlib.h
>2 #include <stdio.h
>3 #include <SDL/SDL.h
4 )][int main(int argc, char *argv
5
{
;6 return 0
}7
إنها شفرة مبدئية ،تشبه الشفرات التي تعوّدنا عليها )تضمين stdlib.hو stdio.hثم .( mainالشيء
الوحيد الذي تغيّر هو تضمين الملف . SDL.hإن ّه ملف رأس ّي يستكلف نفسه بتضمين كل الملفات الرأسية
الخاصة بالمكتبة .SDL
إنشاء مشروع SDLفي Visual C++
استخراج ملفات الـSDL
من الموقع الرسمي ،قم بتنز يل آخر نسخة من المكتبة من قسم ” ”Development Librariesو اختر نسخة Visual
.C++ 2005 Service Pack 1
إفتح الملف . .zip
إنه يحتوي على التوثيق )في المجلد ،( docsالملفات ) .hفي المجلد ،( includeو الملفات ) .libفي
المج ّلد ( libالمكافئة للملفات .aبالنسبة لمترجم .Visualستجد أيضا ًالملف SDL.dllفي المجل ّد . lib
• انسخ الملف SDL.dllإلى مجل ّد المشروع.
• انسخ الملفات .libإلى المجل ّد libالخاص بـ .Visual C++بالنسبة لي ،أنا أتكلم عن المجل ّد
. C:\Program Files (x86)\Microsoft Visual Studio 8\VC\lib
• انسخ الملفات .hإلى المجل ّد includesالخاص بـ .Visual C++أنشئ مجل ّدا SDLفي المجلد
includesلجمع الملفات .hالخاصة بالـ SDLفيه .بالنسبة لي ،سأضع تلك الملفات في المجلد :
. C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\SDL
294
إنشاء مشروع Windows : SDL
إنشاء SDLمشروع جديد
في الـ Visual C++أنشئ مشروعا ً من نوع .Application console Win32سم ّيه مثلا ً testsdlثم اضغط
على ”موافق”.
ستفتح نافذة مساعدة .توجه إلى Application parametersو تأكد من أن الخانة Empty project
مختارة.
لقد تم ّ إنشاء المشروع إذا .إن ّه فارغ .أضف إليه ملفا ً جديدا ً و ذلك بالنقر على Source filesثم
Addثم : New element
295
الفصل ج .1.ٺثبيت الـSDL
حينما تفتح نافذة جديدة ،أطلب إنشاء ملف جديد من نوع ) ، C++ File (.cppقم بتسميته
. main.cبوضعك للامتداد .cفإن الـ Visualسيقوم بانشاء ملف Cو ليس .C++
أكتب )أو انسخ/أل ِصق( الشفرة المبدئية الذي وضعتها أعلاه ،في الملف الجديد الذي أنشأته.
تخصيص مشروع SDLفي Visual C++
التعديل على المشروع أصعب قليلا ً مما هو الحال مع الـ ،Code::Blocksلـكن بقليل من التركيز ،ستتمكن من
فعله .توجّه إلى خصائص المشروع من . testsdl properties / Project
• في القسم Code generation / C / C++ع ّدل قيمة الـ Runtime Librariesإلى
). DLL multithread (/MD
• في القسم Advanced / C / C++اختر Compilation asو ضع القيمة
)) Compile as C code (/TCو إلا فإن Visualسيترجم البرنامج كأنه ملف C++و ليس
كملف .(C
• في القسم Input / Link editorع ّدل قيمة الـ Additional dependenciesلـكي تضيف
SDL.libو . SDLmain.lib
• في القسم System / Link editorع ّدل قيمة الـ Sub-Systemإلى الـ . Windows
قم بالضغط على ”موافق” لحفظ التغييرات.
يمكنك الآن الترجمة و ذلك بالذهاب إلى Generateثم . Generate solution
296
إنشاء مشروع (Xcode) Mac OS : SDL
ستجد الملف التنفيذي الذي يتواجد بمجلد المشروع )أو بمجلد داخلي يسمى ( Debugو لا تنس أنه على
الملف SDL.dllأن يتواجد في نفس المجل ّد الذي يتواجد به الملف التنفيذي .أنقر م ّرتين على ، .exeإذا
سار ك ّل شيء على ما يرام ،فلن يحصل أ ّي شيء ،و إلّا فسيحدث خطأ إذا لم يكن الملف SDL.dllفي
نفس المجل ّد.
ج 4.1.إنشاء مشروع (Xcode) Mac OS : SDL
فلتقم بتحميل النسخة 1.2من الـ ،SDLو ذلك من خلال الجزء ” ”Downloadأسفل يسار الموقع ،كالتالي :
في أسفل الصفحة ستجد قسما ًيدعى ” .”Runtime Librariesنزّل الملف الذي يتناسب مع هندسة معالج
جهازك ) Intelأو ،(PowerPCهذا ما ستوضحه الصورة الموالية .إن كنت تريد معرفة هندسة المعالج ،يمكنك
الذهاب إلى القائمة ” ”Appleفي أعلى اليسار ،و النقر على ” .”About this Macفي السطر ” ”Processorستجد
إما Intelأو .PowerPC
297
الفصل ج .1.ٺثبيت الـSDL
حينما يتم تحميل الملف ،انقر عليه مرتين ،يفترض أن يفتح لوحده .ستجد بهذا المجل ّد مجل ّدا SDL.framework
قم بنسخه و لصقه في المجلد . /Library/Frameworks
إنتهى ،المكتبة مس ّطبة الآن !
ستجد مجل ّدا آخر اسمه devel-liteأتركه مفتوحا ،سنعود إليه لاحقا ً.
الآن قم بانشاء مشروع جديد ” ،”Cocoa Applicationإضغط على ” .”Nextفي Product Nameقم
بتسمية المشروع )كـ” ”SDLمثلا ً( .و في ، Company Identifierضع ما تريد )كاسم مستعار لك
مثلا( .أترك الباقي كما هو ثم اضغط على ” .”Nextاختر أين تريد وضع المشروع .سيتم انشاء مجل ّد بطر يقة تلقائية
و ليس عليك إنشاء واحد بنفسك ووضع ملفات المشروع بداخله.
ما إن يتم إنشاء المشروع ،قم بالتخلص من الملفات التي لا تحتاجها ، AppDelegate.m ، AppDelegate.h :
main.m ، InfoPlist.strings ، MainMenu.xibو : Credits.rtf
298
إنشاء مشروع (Xcode) Mac OS : SDL
اختر المشروع من التفرع الشجري اليساري )القسم Install SDLمن الصورة الموالية( في الشجرة
الثانية اختر اسم مشروعك من قسم PROJECTو ليس من : TARGETS
يمكنك أيضا ًتغيير الـ localisationمن Englishإلى . Frenchاختر ، Englishأنقر على -للمسح
و على +لإضافة ، Frenchهذا يعود إليك و لست مضطرا ً للقيام بذلك.
سنقوم الآن بتخصيص المشروع على نظام ) 32 bitsلأن المكتبة لا تشتغل على أنظمة ،(64 bitsو سنقوم
بإضافة المسارات من أجل الـ ،frameworksو للملفات الرأسية أيضا ً .إضغط على Build Settingsثم
Allثم في Architecturesانقر على 64-bit Intelو اختر : 32-bit Intel
299
الفصل ج .1.ٺثبيت الـSDL
ما إن تفعل ذلك ،اختر LLVM GCC 4.2من السطر . Compiler for C/C++/Objective-C
اذهب إلى منطقة البحث في أعلى اليمين ،و اكتب ” ،”search pathsيجدر بك أن تجد سطرين مهمّين بالنسبة
لنا و هما Header search pathsو . Framework search pathsانقر مرتين على الجهة اليمنى
للسطر Framework search pathsأنقر على علامة +و أضف المسار . /Library/Frameworks
بالنسبة للسطر Header Search pathsأضف المسار
. /Library/Frameworks/SDL.framework/Headers
إختر الآن ”هدفك” ،و هذه المرة من قسم : TARGETS
توجه إلى ، Summaryفي المنطقة Application Categoryيمكنك وضع ما تشاء ،لن يغير هذا
شيئا كبيرا ً ،لأنه ينفع من أجل الـ AppStoreفقط .ع ّدل السطر Main Interfaceو ضع ”.”SDLMain
بالنسبة للـ App Iconفاسمه يدل عليه ،فهو يسمح لك بتحديد أيقونة لبرنامجك .يكفي سحب ثم تحرير الصورة
الم ُراد استعمالها كأيقونة .بالنسبة للمنطقة Linked Frameworks and Librariesسنقوم بإضافة
الـ frameworkالخاص بنا ، SDL.frameworkأنقر على +في منطقة البحث ،أكتب ” ،”SDLحين تجده في
القائمة ،أنقر على ، Addإن لم تجده فهذا يعني أنك لم تقم بوضعه في المجل ّد المناسب ) .( /Library/Frameworks
300