لغة سي C التي تعد واحدة من أقوى لغات البرمجة وأكثرها عراقة في تاريخ علوم الحاسوب وهندسة البرمجيات. فهي اللغة التي اعتمدت عليها كثير من لغات البرمجة، وطورت باستخدامها معظم أنظمة التشغيل. وعلى الرغم من ظهور العديد من لغات البرمجة الأحدث منها لا تزال لغة البرمجة C حتى اليوم لغة منتشرة ومستخدمة في العديد من التطبيقات والمجالات لما توفره من ميزات وخصائص لا تتوفر في غيرها.

ما هي لغة سي C

لغة سي C هي لغة برمجة عامة الأغراض طورها المبرمج دينيس ريتشي Dennis Ritchie من شركة Bell Labs عام 1972 بهدف إيجاد لغة برمجة فعالة ومفهومة تصلح لبرمجة أنظمة التشغيل، فكانت لغة سي C التي اتسمت ببساطتها وقوتها ووفرت إمكانية الوصول المباشر لموارد الحاسوب.

كما استخدمت لغة سي لبرمجة نظام التشغيل يونكس Unix المُطوَّر كذلك في شركة Bell Labs فقد كانت نواة يونكس مكتوبة بلغة التجميع assembly وهي لغة برمجة منخفضة المستوى. ثم نقلت للغة C التي تفوقت عليها وتمكنت من تأدية مهامها بنفس الكفاءة وبعدد أقل من أسطر التعليمات البرمجية وهذا زاد من قوتها وشهرتها وبدأ استخدامها في العديد من المجالات والتطبيقات العديدة الأخرى.

ستجد أن لغة C تصنف وفق عدة مستويات للغات البرمجة فبعض المراجع تصنفها على أنها لغة برمجة عالية المستوى high level programming language في حين تصنفها مراجع أخرى بأنها لغة برمجة متوسطة المستوى medium level programming language لكونها تتضمن العديد من الميزات والوظائف منخفضة المستوى وعالية المستوى بنفس الوقت، ويمكن اعتبارها كلغة وسيطة بين اللغات منخفضة المستوى المنخفض مثل لغة الآلة أو لغة التجميع، واللغات عالية المستوى مثل لغة جافا أو بايثون.

كما تسمى لغة البرمجة C بأم لغات البرمجة حيث اعتمدت معظم لغات البرمجة الأحدث مثل C++‎ و C#‎ وجافا وبايثون و PHP وجو Go على طريقتها وأسلوبها في كتابة التعليمات ولهذا السبب ستجد أن لغة سي C أول لغة برمجة يقرر تعليمها لطلاب كليات هندسة البرمجيات وعلوم الحاسوب والتعرف على أساسيات البرمجة من خلالها. فتعلم هذه اللغة يوفر الأساس المتين الذي يمكن المبرمج من فهم أكواد أي لغة برمجة أخرى بسهولة أكبر واحتراف حل المشكلات البرمجية وبعد تعلمها لن يصعب عليه تعلم أي لغة برمجة أخرى.

استخدامات لغة سي C

تستخدم لغة C في مجموعة منوعة من التطبيقات والمجالات ومن أبرز استخداماتها:

  • تطوير أنظمة التشغيل فنواة نظام التشغيل يونكس UNIX ولينكس Linux وويندوز Windows ونواة أنظمة Apple OS X كلها مكتوبة بلغة سي C.
  • برمجة التطبيقات المساعدة لنظام التشغيل فمعظم متصفحات الويب على سبيل المثال مبرمجة بلغة C كما أن معظم إضافات المتصفحات مكتوبة بها.
  • تطوير لغات البرمجة ومصرفاتها Compilers أو مفسراتها Interpreters وهي عبارة عن برامج تحول أو تترجم لغات البرمجة عالية المستوى إلى لغة الآلة، على سبيل المثال مفسر لغة بايثون Python Interpreter مطور باستخدام لغة C.
  • برمجة التطبيقات المضمنة وتطبيقات انترنت الأشياء IoT والأنظمة المدمجة وبرمجة المتحكمات الدقيقة المستخدمة في برمجة الأجهزة الذكية كالسيارات ذاتية القيادة أو الروبوتات الذكية لما توفره من تحكم مباشر بالعتاد.
  • بناء قواعد البيانات فالعديد من أنظمة إدارة قواعد البيانات المعروفة مثل أوراكل Oracle و MySQL و PostgreSQL تستخدم لغة C.
  • تعد لغة C كذلك لغة مثالية لبرمجة تطبيقات سطح المكتب فعالة وعالية الأداء، فهي تمكن المطور من الوصول بسهولة لموارد الحاسوب كالمعالج والذاكرة والتحكم في أداء التطبيق بمرونة كبيرة.
  • برمجة الألعاب الإلكترونية وتطوير محركات الألعاب Game Engines ومن أشهر الألعاب المطورة باستخدام لغة سي C لعبة Quake و Doom.
  • تطوير خوادم الويب الكبيرة التي تحتاج إلى التعامل مع عدد كبير من الطلبات في وقت واحد و معالجة البيانات بسرعة مثل خادم أباتشي Apache أو إنجن إكس Nginx
  • وبالعموم تصلح لغة سي بشكل عام لتطوير كافة التطبيقات عالية الأداء التي تحتاج لإنجاز الكثير من العمليات أو تتطلب معالجة كمية ضخمة من البيانات بسرعة.

مميزات لغة سي C

  • لغة C مشهورة على نطاق واسع فهي واحدة من أكثر لغات البرمجة شعبية بين المطورين.
  • لغة منظمة ومستقلة عن نظام التشغيل حيث يمكن تصريف تعليماتها للعمل على منصات وأنظمة مختلفة مثل ويندوز Windows ولينكس Linux وماك macOS وأندرويد Android.
  • تشكل لغة سي الأساس للعديد من اللغات الأخرى فمعظم لغات البرمجة الحديثة تتبع أسلوبها في كتابة التعليمات.
  • تتبع لغة البرمجة C نموذج البرمجة الإجرائية procedural programming language التي تعتمد على تقسيم المشكلة إلى سلسلة من الإجراءات أو الخطوات التي تستدعى بترتيب معين لحل المشكلة وهذا الأسلوب سهل في التعلم والفهم.
  • توفر لغة C وصولاً مباشرًا إلى موارد النظام وإدارة الذاكرة والتحكم بها وتخصيصها ما يساعد على تطوير برامج فعالة عالية الكفاءة.
  • تعد لغة سي قابلة للتوسيع وتوفر للمطورين مفهوم المكتبات libraries التي توسع وظائف اللغة كما تحتوي على العديد من المكتبات المضمنة التي توفر للمطورين وظائف جاهزة للاستخدام.
  • لغة C متعددة الاستخدامات حيث يمكن استخدامها لتطوير أنظمة التشغيل وبرامج تشغيل الأجهزة والألعاب وأنظمة قواعد البيانات وغيرها
    من التطبيقات العديدة الأخرى.
  • تعد C من لغات البرمجة المصرفة compiled وهي أسرع من لغات البرمجة المُفسرة interpreted.

عيوب لغة سي C

  • لا تدعم لغة سي مبدأ البرمجة كائنية التوجه OOP بشكل ضمني وتدعم فقط نموذج البرمجة الإجرائية وهذا يجعل إعادة استخدام الشيفرة محدود ويصعب صيانة البرامج الكبيرة، لكن هناك مكتبات يمكن أن توسع ميزات اللغة وتضيف لها بعض الميزات كائنية التوجه للغة مثل مكتبة OOPC.
  • تجبرك لغة سي C على تحديد نوع المتغير عند التصريح عنه، لكنها لا تفرض قيودًا صارمة على أنواع المتغيرات. حيث يمكنك على سبيل المثال تعريف متغير من نوع عدد صحيح int واستخدامه لاحقًا لتخزين قيمة من نوع عدد حقيقي float وهذا قد يؤدي إلى وقوع بعص الأخطاء في البرنامج.
  • تتحقق لغة C من الأخطاء البرمجية وقت تشغيل الكود “runtime” مما يصعب عملية فحص الكود وتصحيح الأخطاء البرمجية خاصة في المشاريع الضخمة.
  • لا تدعم لغة C مفهوم الاستثناءات exceptions وهو مفهوم برمجي يسهل تحديد الأخطاء البرمجية وتصحيحها.
  • لا تدعم لغة C مفهوم فضاءات الأسماء namespace التي تعد من الميزات البرمجية المفيدة في منع تضارب بين أسماء المتغيرات أو الوظائف وتساعد في تنظيم التعليمات البرمجية.

الفرق بين لغة C ولغة C++‎

تعد لغة ++C امتدادًا للغة البرمجة C، فهي لغة برمجة عامة الأغراض طورها بيارن ستروستروب Bjarne Stroustup عام 1979 لتكون مزيجًا من لغة C ومن الأصناف البرمجية Classes فهي تدعم كلاً من نموذج البرمجة الإجرائية المتبع في لغة C كما تدعم نموذج البرمجة كائنية التوجه بنفس الوقت.

حيث تحتوي لغة C++‎ على جميع ميزات لغة سي C مثل التوافق مع معظم بيئات التشغيل وإدارة الذاكرة بصورة فعالة وتوفير مكتبة غنية من الوظائف البرمجية، كما تضيف لها ميزات أخرى عديدة لزيادة كفاءتها على سبيل المثال تدعم C++‎ معالجة الاستثناءات وميزة فضاءات الأسماء وميزات حماية البيانات وغيرها من الميزات غير المدعومة في لغة C بشكل ضمني.

يمكن القول أن لغة C مناسبة أكثر لبرمجة التطبيقات منخفضة المستوى مثل أنظمة التشغيل وبرامج تشغيل الأجهزة التي تحتاج لمقدار كبير من التحكم بالعتاد، في حين تعد لغة C++‎ مناسبة أكثر لتطوير التطبيقات الأكثر تعقيدًا والتي تحتاج لمستوى أمان عالي وسرعة في الأداء.

خطوات تعلم لغة سي C

إليك أهم الخطوات الرئيسية التي تساعدك على تعلم لغة ?

  • قبل البدء بخطوات تعلم لغة سي حاول أن تفهم مبادئ الخوارزميات والتفكير المنطقي فهي خطوة أساسية تسرع زمن تعلم البرمجة.
  • تعلم تثبيت مصرف لغة C على جهازك ومحرر لكتابة الأكواد البرمجية وجرب كتابة البرنامج الأول وتصريفه وتشغيله.
  • ابدأ بتعلم المفاهيم الأساسية للبرمجة بهذه اللغة مثل تعريف المتغيرات وانواعها واستخداماتها وإجراء العمليات عليها واستخدام عبارات التحكم مثل الشروط والحلقات والمصفوفات والاتحادات والسلاسل وغيرها من هياكل البيانات. ومفهوم الدوال البرمجية وطريقة استخدامها.
  • طبق ما تتعلمه من مفاهيم أساسية على كتابة بعض البرامج بسيطة بلغة سي وتأكد من أنك فهمت الأساسيات جيدًا وتدربت على استكشاف الأخطاء وإصلاحها قبل أن تنتقل للخطوة التالية.
  • ابدأ بدراسة مواضيع متقدمة مثل المؤشرات والقوائم المتسلسلة وتعلم أساليب تخصيص الذاكرة الديناميكية والتعامل مع الملفات.
  • حدد نوع التطبيقات العملية الذي تهتم به وتعرف على أهم المكتبات والأدوات التي تساعدك على تطوير هذا النوع من التطبيقات. على سبيل المثال إذا كنت مهتمًا بتطوير التطبيقات المضمنة فعليك الاهتمام بأمور المتحكمات الدقيقة ومنافذها والتحكم بالذاكرة بشكل فعال. والبدء ببناء تطبيقات عملية تعزز خبراتك وتساعدك على بناء معرض أعمال والحصول على فرصة عمل مناسبة.
  • ستجد الكثير من مصادر تعلم لغة C من دروس ومنتديات ومقاطع فيديو وكتب ودورات تدريبية وغيرها. لكن أنصحك أن لا تشتت نفسك بكثرة المصادر وركز على تعلم موثوقة تناسب أسلوبك في التعلم.

بنية برنامج لغة سي C

إذا كنت معتادًا على لغات تتبع بنية الكُتل مثل لغة باسكال Pascal، فستجد بنية برنامج لغة سي C مفاجئًا لك. وإذا كانت خبرتك في مجال لغات مشابهة للغة فورتران FORTRAN. فستجد البنية مشابهةً لما اعتدت عليه -بالرغم من اختلافها بصورةٍ كبيرة في التفاصيل. وفي الحقيقة استعارت لغة سي من كلا الأسلوبين المُستخدمين بصورةٍ واضحة، ومن أماكن أخرى أيضًا. نتيجةً لأخذ بعض القواعد من مصادر مختلفة، تبدو لغة سي أشبه بنتيجة تزاوج فصيلة كلاب ترير Terrier. غير الأنيقة والمعروفة بعنادها وقوتها لكنها متسامحة مع أفراد العائلة. يطلق علماء الأحياء على هذا النوع من الفصائل “القوة الهجينة”. قد يذكرك كلامنا أيضًا بمخلوق كمير Chimera الأسطوري الذي يبدو خليطًا من الخرفان والماعز. قد يمنحنا الحليب والصوف، ولكنه سيزعجنا بثغائه المرتفع ورائحته غير اللطيفة.

إذا نظرنا للأمر عمومًا نلاحظ أن ميزة لغة سي C العامة هي بنية البرنامج الموزعة على عدة ملفات. لأنها تسمح بتصريف منفصل لهذه الملفات، إذ تسمح لغة سي بتوزيع أجزاء من برنامج مكتمل على عدة ملفات مصدرية. والتصريف على نحوٍ متفرق عن بعضها بعضًا. مبدأ العمل هنا هو أن جميع عمليات التصريف هذه ستعطينا ملفات يمكن ربطها Linked سويًّا عن طريق أي محرر ربط. أو محمّل ربط يستخدمه نظامك، ولكن بنية الكتل لبعض لغات البرمجة المشابهة للغة ألغول ALGOL تجعل هذه الطريقة صعبة التنفيذ. نظرًا لأن البرنامج مكتوبٌ بطريقة تجعل منه كتلةً واحدةً مترابطة، إلا أن هناك بعض الطرق للتغلُّب على هذه المشكلة.

تتغلب لغة سي على هذه المشكلة بطريقةٍ مثيرة للاهتمام، إذ من المفترض أن تسرّع عملية التصريف. لأن تصريف البرنامج إلى تعليمات مصرَّفة Object Code بطيء ومكلف من ناحية الموارد، فالتصريف عملية شاقة. أتت من هنا فكرة استخدام المحمّل في ربط مجموعة من التعليمات المصرفة. إذ تتطلب هذه العملية ترتيب التعليمات حسب عنوانها للتوصل للبرنامج الكامل ببساطة. يُفترض أن يكون هذا الحل خفيف الاستهلاك للموارد، وعلى المحمّل طبعًا فحص المكتبات المستخدمة في التعليمات المصرفة واختيارها أيضًا.

الفائدة المكتسبة هنا هو أننا لسنا بحاجة تصريف كامل البرنامج بعد تعديل جزءٍ بسيط منه. في هذه الحالة نحن بحاجة إعادة تصريف الجزء المُعدّل من البرنامج فقط. ولكن قد يصبح المحمّل في بعض الأحيان أبطأ عمليات تصريف البرنامج وأكثرها استهلاكًا للموارد بزيادة العمل المطلوب منه. وقد تكون العملية أسرع في بعض الأنظمة إذا صُرّف كل شيء دفعةً واحدة. وتُعد لغة أدا Ada إحدى الأمثلة المعروفة باتباعها لهذا الأسلوب. بالنسبة للغة سي فالعمل المنجز من المصرف ليس ضخمًا ومعقول إلى حدٍّ ما. يوضح الشكل 1.1 طريقة عمل المصرف في لغة سي.

هذه الطريقة مهمة في لغة سي. إذ من الشائع أن تجد جميع البرامج باستثناء الصغيرة منها مؤلفةٌ من عددٍ من ملفات الشيفرة المصدرية. هذا يعني أيضًا أن جميع البرامج مهما كانت بسيطة ستمرّ بالمحمّل. نظرًا لاعتماد لغة سي المكثف على المكتبات، وهذا ما قد يكون غير واضح عند النظرة الأولى أو للمتعلّم الجديد.

الدوال

تتكون لغة C من مجموعة عناصر تشكل لبنات البناء الأساسية لها. مثل الدوالّ Functions وما نطلق عليه تسمية المتغيرات العامة global variables. إذ تُسمى هذه العناصر في نقطة ما من البرنامج عند تعريفها. وتحتوي طريقة الوصول لهذه العناصر باستخدام اسمائهم ضمن البرنامج على بعض القواعد، وتُوصف هذه القواعد في المعيار بمصطلح الربط Linkage. سنتكلم في الوقت الحالي فقط عن الربط الخارجي External Linkage وانعدام الربط No linkage. إذ تُدعى العناصر التي يمكن الوصول إليها ضمن البرنامج كاملًا، مثل دوال مكتبة معينة. بعناصر الربط الخارجي، وتُستخدم العناصر عديمة الربط بكثرة أيضًا ولكن الوصول إليها محدودٌ بصورةٍ أكبر.

تُسمى المتغيرات المستخدمة داخل الدالة بالمتغيرات “المحلية Local” وهي عديمة الربط. وعلى الرغم من أننا نتفادى المصطلحات المعقدة قدر الإمكان في هذا الكتاب مثل المصطلحات التي ذكرناها سابقًا. ولكن لا توجد طريقة أبسط من شرح هذه المصطلحات. ستألف مصطلح الربط ضمن هذا الكتاب، والنوع الوحيد من الربط الخارجي الذي ستراه حاليًّا هو استخدام الدوال.

تكافئ الدوال في لغة سي الدوال والبرامج الفرعية في لغة فورتران FORTRAN والدوال والإجراءات في لغة باسكال Pascal وألغول ALGOL. بينما لا تمتلك لغة بيسك BASIC ومعظم طفراتها mutations البسيطة أو لغة كوبول COBOL مقدار الدوال التي تمتلكه لغة سي.

الفكرة من الدالة بسيطة وتتمثّل بإعطائك الإمكانية بتضمين فكرةٍ واحدة أو عملية ضمن قالب. وإعطائها اسمًا ما واستدعائها ضمن أجزاءٍ مختلفة من برنامجك باستخدام اسمها فقط. تكون تفاصيل العملية هذه غير واضحة عند ذكر الاسم ضمن البرنامج، وهذا الأمر طبيعي. وفي البرامج المصممة المهيكلة بصورةٍ جيدة. يمكنك تغيير طريقة عمل دالة ما (شرط ألّا يغير ذلك من طبيعة العمل) دون أن تؤثر على الأجزاء الأخرى من البرنامج.

تعريف وتصريح الدالة

التصريح

نلاحظ وجود ما يُسمى تصريح الدالة function declaration بعد تضمين ملف <stdio.h>، الذي يخبر المصرّف أن show_message دالة لا تأخذ أي وسيط ولا تُعيد أي قيمة، ويوضح لنا هذا تغييرًا جرى على المعيار، ألا وهو النموذج الأولي للدالة function prototype، وسنناقش هذا الموضوع بتوسّع لاحقًا. ليس من الضروري التصريح عن الدالة مسبقًا، إذ ستستخدم لغة سي بعض القواعد القديمة الافتراضية. في هذه الحالة، إلا أنه ينصح بشدة التصريح عن الدالة في البداية.

الفرق بين التصريح والتعريف هو أن التصريح يصف نوع الدالة والوسطاء المُمرّرة له. بينما يحتوي التعريف على بنية الدالة بالكامل. سيهمّنا فهم الفرق بين المصطلحين لاحقًا.

يستطيع المصرّف تفقد استعمال الدالة show_message فيما إذا كان صحيحًا أم لا بالتصريح المُسبق عنها قبل استخدامها. ويصف التصريح ثلاث خصائص عن الدالة، هي: اسمها ونوعها وعدد الوسطاء ونوعهم. إذ يشير الجزء )void show_message إلى نوع الدالة والقيمة التي تُعيدها بعد استدعائها وهي void (سنناقش معناها لاحقًا). نستطيع رؤية الاستخدام الثاني لكلمة void في قائمة الوسطاء للدالة (void)، والذي يعني أن الدالة لا تقبل أي وسطاء.

التعريف

تلاحظ في نهاية البرنامج تعريف الدالة، وبالرغم من أنّ أن طولها ثلاث أسطر فقط. إلا أنها تُعد مثالًا على تعريف دالة متكامل.

تنفِّذ دوال لغة سي المهام التي قد تقسِّمها بعض اللغات الأخرى إلى جزأين. إذ تستخدم لغات البرمجة الدوال لإعادة قيمةٍ ما، مثل دالة الجيب المثلثي sin وجيب التمام cos أو ربما دالة تُعيد الجذر التربيعي لعددٍ ما. وهذه الطريقة التي تعمل بها دوالّ لغة سي، بينما تجري بعض لغات البرمجة هذه العملية باستخدام ما يشبه الدوال ولكن الفرق هنا هو عدم إعادة القيمة. مثل استخدام فورتران للبرامج الفرعية واستخدام باسكال وألغول للإجراءات. تنجز لغة سي كل هذه المهام باستخدام الدوال عن طريق تحديد نوع القيمة المُعادة عند التصريح عن الدالة، ولا تُعيد الدالة show_message أي قيمة، لذلك نوعها void.

إما أن يكون استخدام القيمة void بديهيًّا لك، أو صعب الفهم حسب الطريقة التي تنظر لها للأمر. ففي الحقيقة، يمكننا الدخول في نقاشات فلسفيّة جانبية وغير مثمرة عن كون void يصف نوع قيمةٍ أو لا. لكن أفضل تجنب ذلك. بغض النظر عن رأيك، استخدام النوع void التي تعني: “أنا لا أهتم بأي قيمة ترجعها هذه الدالة (أو لا ترجعها)”.

إذًا، نوع الدالة هو void واسمها show_message، أما القوسان () اللذان يتبعان هذه المعلومات، فهما لتنبيه المصرّف أننا نقصد التعريف، أو التصريح عن دالة. إذا كانت الدالة تقبل أي وسيط، فيجب وضع اسمه داخل القوسين. الدالة التي نتكلم عليها في مثالنا لا تأخذ أي وسطاء وهذا الأمر موضّح عن طريق استعمال الكلمة void بداخل القوسين. وبالتالي اتّضح أن للكلمة التي تصف الفراغ والرفض أهميّةٌ بالغة.

يشكّل متن الدالة تعليمة مركبة compound statement، وهي مجموعةٌ من التعليمات المُحاطة بأقواس معقوصة {}. على الرغم من وجود تعليمة واحدة فقط إلا أن الأقواس مطلوبة، وعمومًا. تسمح لك لغة سي باستخدام تعليمة مركبة في أي مكان تسمح به عادةً باستخدام تعليمة واحدة بسيطة. وتهدف الأقواس المعقوصة لتحويل عدة تعليمات متتالية إلى تعليمة واحدة.