بعد كل هذه السنوات ، لا يزال العالم مدعومًا ببرمجة لغة سي
نشرت: 2022-03-11بدأ العديد من مشاريع C الموجودة اليوم منذ عقود.
بدأ تطوير نظام التشغيل UNIX في عام 1969 ، وتمت إعادة كتابة كوده في C في عام 1972. تم إنشاء لغة C فعليًا لنقل كود نواة UNIX من التجميع إلى لغة ذات مستوى أعلى ، والتي ستؤدي نفس المهام مع عدد أقل من سطور التعليمات البرمجية .
بدأ تطوير قاعدة بيانات Oracle في عام 1977 ، وأعيدت كتابة كودها من التجميع إلى C في عام 1983. وأصبحت واحدة من أكثر قواعد البيانات شيوعًا في العالم.
في عام 1985 ، تم إصدار Windows 1.0. على الرغم من أن كود مصدر Windows غير متاح للجمهور ، فقد ذكر أن النواة الخاصة به مكتوبة في الغالب بلغة C ، مع بعض الأجزاء في التجميع. بدأ تطوير Linux kernel في عام 1991 ، وهو مكتوب أيضًا في C. وفي العام التالي ، تم إصداره بموجب ترخيص GNU وتم استخدامه كجزء من نظام التشغيل GNU. بدأ نظام التشغيل GNU نفسه باستخدام لغات البرمجة C و Lisp ، لذلك فإن العديد من مكوناته مكتوبة بلغة C.
لكن برمجة لغة سي لا تقتصر على المشاريع التي بدأت منذ عقود ، عندما لم يكن هناك العديد من لغات البرمجة كما هو الحال اليوم. لا تزال العديد من مشاريع C تبدأ حتى اليوم ؛ هناك بعض الأسباب الوجيهة لذلك.
كيف يتم تشغيل العالم بواسطة سي؟
على الرغم من انتشار اللغات عالية المستوى ، تواصل لغة C تمكين العالم. فيما يلي بعض الأنظمة التي يستخدمها الملايين والمبرمجة بلغة C.
مايكروسوفت ويندوز
تم تطوير Microsoft Windows kernel في الغالب بلغة C ، مع بعض الأجزاء في لغة التجميع. لعقود من الزمان ، كان نظام التشغيل الأكثر استخدامًا في العالم ، والذي يحتوي على حوالي 90 في المائة من حصة السوق ، مدعومًا بنواة مكتوبة بلغة C.
لينكس
Linux أيضًا مكتوب في الغالب بلغة C ، مع بعض الأجزاء في التجميع. حوالي 97 بالمائة من أقوى 500 حاسوب خارق في العالم يشغلون نواة لينكس. كما أنها تستخدم في العديد من أجهزة الكمبيوتر الشخصية.
ماك
يتم تشغيل أجهزة كمبيوتر Mac أيضًا بواسطة C ، نظرًا لأن OS X kernel مكتوب في الغالب باللغة C.
متحرك
نواة iOS و Android و Windows Phone مكتوبة أيضًا في C. فهي مجرد تعديلات محمولة لنظام التشغيل Mac OS و Linux و Windows kernels. لذا فإن الهواتف الذكية التي تستخدمها كل يوم تعمل على نواة سي.
قواعد بيانات
يتم ترميز قواعد البيانات الأكثر شيوعًا في العالم ، بما في ذلك Oracle Database و MySQL و MS SQL Server و PostgreSQL ، في لغة C (أول ثلاثة منها في الواقع في C و C ++).
تُستخدم قواعد البيانات في جميع أنواع الأنظمة: المالية ، الحكومية ، وسائل الإعلام ، الترفيه ، الاتصالات ، الصحة ، التعليم ، البيع بالتجزئة ، الشبكات الاجتماعية ، الويب ، وما شابه ذلك.
أفلام ثلاثية الأبعاد
يتم إنشاء الأفلام ثلاثية الأبعاد باستخدام تطبيقات تمت كتابتها بشكل عام بلغة C و C ++. يجب أن تكون هذه التطبيقات فعالة وسريعة للغاية ، لأنها تتعامل مع كمية هائلة من البيانات وتقوم بالعديد من العمليات الحسابية في الثانية. كلما زادت فعاليتها ، قل الوقت الذي يستغرقه الفنانون ورسامو الرسوم المتحركة لإنشاء لقطات الفيلم ، وكلما زادت الأموال التي توفرها الشركة.
الأنظمة المضمنة
تخيل أنك تستيقظ ذات يوم وتذهب للتسوق. من المحتمل أن المنبه الذي يوقظك مبرمج في C. ثم تستخدم الميكروويف أو آلة صنع القهوة لتحضير وجبة الإفطار. إنها أيضًا أنظمة مضمنة ، وبالتالي من المحتمل أن تكون مبرمجة في C. تقوم بتشغيل التلفزيون أو الراديو أثناء تناول وجبة الإفطار. هذه أيضًا أنظمة مدمجة ، مدعومة من C.
ثم تدخل سيارتك. إذا كان يحتوي على الميزات التالية ، تمت برمجته أيضًا في C:
- إنتقال تلقائي
- أنظمة كشف ضغط الإطارات
- أجهزة الاستشعار (الأكسجين ، درجة الحرارة ، مستوى الزيت ، إلخ)
- ذاكرة للمقاعد وإعدادات المرآة.
- عرض لوحة القيادة
- الفرامل المضادة للقفل
- التحكم التلقائي في الثبات
- مثبت السرعة
- التحكم في المناخ
- أقفال واقية من الأطفال
- دخول بدون مفتاح
- مقاعد ساخنة
- التحكم بالوسادة الهوائية
تصل إلى المتجر ، وتوقف سيارتك وتذهب إلى آلة البيع للحصول على الصودا. ما اللغة التي استخدموها لبرمجة آلة البيع هذه؟ ربما C. ثم تشتري شيئًا من المتجر. يتم برمجة آلة تسجيل المدفوعات النقدية أيضًا في C. ومتى تدفع ببطاقتك الائتمانية؟ لقد خمنت ذلك: من المحتمل أن يكون قارئ بطاقات الائتمان ، مرة أخرى ، مبرمجًا بلغة C.
كل هذه الأجهزة هي أنظمة مدمجة. إنها مثل أجهزة الكمبيوتر الصغيرة التي تحتوي على متحكم / معالج دقيق بداخلها يقوم بتشغيل برنامج ، يسمى أيضًا البرامج الثابتة ، على الأجهزة المضمنة. يجب أن يكتشف هذا البرنامج ضغطات المفاتيح ويتصرف وفقًا لذلك ، ويعرض أيضًا المعلومات للمستخدم. على سبيل المثال ، يجب أن يتفاعل المنبه مع المستخدم ، ويكتشف الزر الذي يضغط عليه المستخدم ، وأحيانًا ، كم من الوقت يتم الضغط عليه ، وبرمجة الجهاز وفقًا لذلك ، كل ذلك أثناء عرض المعلومات ذات الصلة للمستخدم. على سبيل المثال ، يجب أن يكون نظام المكابح المانعة للانغلاق في السيارة قادرًا على اكتشاف الانغلاق المفاجئ للإطارات والعمل على تحرير الضغط على الفرامل لفترة قصيرة من الوقت ، وفتح قفلها ، وبالتالي منع الانزلاق غير المنضبط. كل هذه الحسابات تتم بواسطة نظام مضمن مبرمج.
على الرغم من أن لغة البرمجة المستخدمة في الأنظمة المضمنة يمكن أن تختلف من علامة تجارية إلى أخرى ، إلا أنها تتم برمجتها بشكل شائع بلغة C ، نظرًا لميزات اللغة المتمثلة في المرونة والكفاءة والأداء والقرب من الأجهزة.
لماذا لا تزال لغة البرمجة C مستخدمة؟
يوجد اليوم العديد من لغات البرمجة التي تسمح للمطورين بأن يكونوا أكثر إنتاجية من لغة C لأنواع مختلفة من المشاريع. هناك لغات ذات مستوى أعلى توفر مكتبات مضمنة أكبر بكثير تعمل على تبسيط العمل مع JSON و XML و UI وصفحات الويب وطلبات العميل واتصالات قواعد البيانات ومعالجة الوسائط وما إلى ذلك.
ولكن على الرغم من ذلك ، هناك الكثير من الأسباب للاعتقاد بأن برمجة لغة سي ستظل نشطة لفترة طويلة.
في لغات البرمجة ، حجم واحد لا يناسب الجميع. فيما يلي بعض الأسباب التي تجعل لغة C لا تقبل المنافسة ، وشبه إلزامية ، لبعض التطبيقات.
قابلية وكفاءة
لغة C هي لغة تجميع محمولة تقريبًا. إنه قريب من الجهاز قدر الإمكان بينما يكون متاحًا عالميًا تقريبًا لهياكل المعالجات الحالية. يوجد مترجم C واحد على الأقل لكل معمارية موجودة تقريبًا. وفي الوقت الحاضر ، نظرًا للثنائيات المحسّنة للغاية التي تم إنشاؤها بواسطة المجمّعين الحديثين ، فليس من السهل تحسين مخرجاتهم من خلال التجميع المكتوب يدويًا.
هذه هي قابليتها للنقل وكفاءتها أن "المجمعين والمكتبات والمترجمين الفوريين للغات البرمجة الأخرى يتم تنفيذها غالبًا في لغة C". اللغات المفسرة مثل Python و Ruby و PHP لها تطبيقاتها الأساسية مكتوبة بلغة C. بل إنها تستخدم من قبل المترجمين للغات أخرى للتواصل مع الجهاز. على سبيل المثال ، C هي اللغة الوسيطة الكامنة وراء Eiffel و Forth. هذا يعني أنه بدلاً من إنشاء رمز آلة لكل بنية يتم دعمها ، يقوم المترجمون لهذه اللغات فقط بإنشاء رمز C وسيط ، ويتولى مترجم C إنشاء رمز الجهاز.
أصبحت لغة C أيضًا لغة مشتركة للتواصل بين المطورين. كما قال أليكس ألين ، مدير هندسة Dropbox ومؤسس Cprogramming.com:
لغة C هي لغة رائعة للتعبير عن الأفكار الشائعة في البرمجة بطريقة يشعر بها معظم الناس بالراحة. علاوة على ذلك ، فإن الكثير من المبادئ المستخدمة في لغة سي - على سبيل المثال ،
argc
وargv
لمعلمات سطر الأوامر ، بالإضافة إلى إنشاءات الحلقة وأنواع المتغيرات - ستظهر في الكثير من اللغات الأخرى التي تتعلمها حتى تتمكن من التحدث للأشخاص حتى لو لم يعرفوا لغة C بطريقة مشتركة بينكما.
التلاعب بالذاكرة
يعد الوصول إلى عنوان الذاكرة التعسفي وحساب المؤشر ميزة مهمة تجعل لغة C مناسبة تمامًا لبرمجة النظام (أنظمة التشغيل والأنظمة المضمنة).
عند حدود الأجهزة / البرامج ، تقوم أنظمة الكمبيوتر والميكروكونترولر بتعيين أجهزتها الطرفية ودبابيس الإدخال / الإخراج في عناوين الذاكرة. يجب أن تقرأ تطبيقات النظام وتكتب في مواقع الذاكرة المخصصة هذه للتواصل مع العالم. لذا فإن قدرة C على معالجة عناوين الذاكرة العشوائية أمر حتمي لبرمجة النظام.
يمكن هندسة وحدة التحكم الدقيقة ، على سبيل المثال ، بحيث يتم إرسال البايت الموجود في عنوان الذاكرة 0x40008000 بواسطة جهاز الاستقبال / المرسل العالمي غير المتزامن (أو UART ، وهو مكون جهاز شائع للتواصل مع الأجهزة الطرفية) في كل مرة يتم تعيين رقم البت 4 من العنوان 0x40008001 إلى 1 ، وبعد ضبط هذا البت ، سيتم إلغاء ضبطه تلقائيًا بواسطة الطرف.
سيكون هذا رمزًا لوظيفة C ترسل بايتًا عبر UART:
#define UART_BYTE *(char *)0x40008000 #define UART_SEND *(volatile char *)0x40008001 |= 0x08 void send_uart(char byte) { UART_BYTE = byte; // write byte to 0x40008000 address UART_SEND; // set bit number 4 of address 0x40008001 }
سيتم توسيع السطر الأول من الوظيفة إلى:

*(char *)0x40008000 = byte;
يخبر هذا السطر المترجم أن يفسر القيمة 0x40008000
كمؤشر إلى char
، ثم لإحالة (إعطاء القيمة المشار إليها) هذا المؤشر (مع عامل التشغيل *
الموجود في أقصى اليسار) وأخيراً تعيين قيمة byte
إلى هذا المؤشر الذي تم إلغاء الإشارة إليه. بمعنى آخر: اكتب قيمة byte
المتغير لعنوان الذاكرة 0x40008000
.
سيتم توسيع السطر التالي إلى:
*(volatile char *)0x40008001 |= 0x08;
في هذا السطر ، نقوم بإجراء عملية أو عملية أحادي الاتجاه على القيمة الموجودة على العنوان 0x40008001
والقيمة 0x08
( 00001000
بالثنائي ، أي 1 في رقم البت 4) ، ونحفظ النتيجة مرة أخرى على العنوان 0x40008001
. بمعنى آخر: قمنا بتعيين البت 4 من البايت الموجود على العنوان 0x40008001. نعلن أيضًا أن القيمة على العنوان 0x40008001
متقلبة . يخبر هذا المترجم أنه يمكن تعديل هذه القيمة من خلال عمليات خارجة عن الكود الخاص بنا ، لذلك لن يقوم المترجم بوضع أي افتراضات حول القيمة الموجودة في هذا العنوان بعد الكتابة إليه. (في هذه الحالة ، لا يتم ضبط هذا البت بواسطة جهاز UART بعد أن قمنا بتعيينه بواسطة البرنامج.) هذه المعلومات مهمة لمحسن المترجم. إذا فعلنا ذلك داخل حلقة for
، على سبيل المثال ، دون تحديد أن القيمة متقلبة ، فقد يفترض المترجم أن هذه القيمة لا تتغير أبدًا بعد تعيينها ، ويتخطى تنفيذ الأمر بعد الحلقة الأولى.
الاستخدام الحتمي للموارد
ميزة اللغة الشائعة التي لا يمكن لبرمجة النظام الاعتماد عليها هي جمع البيانات المهملة ، أو حتى مجرد تخصيص ديناميكي لبعض الأنظمة المضمنة. التطبيقات المضمنة محدودة للغاية من حيث الوقت وموارد الذاكرة. غالبًا ما يتم استخدامها لأنظمة الوقت الفعلي ، حيث لا يمكن توفير دعوة غير حتمية لمجمع القمامة. وإذا تعذر استخدام التخصيص الديناميكي بسبب نقص الذاكرة ، فمن المهم جدًا وجود آليات أخرى لإدارة الذاكرة ، مثل وضع البيانات في عناوين مخصصة ، كما تسمح بذلك مؤشرات C. لن تكون اللغات التي تعتمد بشكل كبير على التخصيص الديناميكي وجمع البيانات المهملة مناسبة للأنظمة محدودة الموارد.
حجم الكود
C لديه وقت تشغيل صغير جدًا. وبصمة الذاكرة لرمزها أصغر من معظم اللغات الأخرى.
عند مقارنتها بـ C ++ ، على سبيل المثال ، يكون حجم الملف الثنائي الذي يتم إنشاؤه بواسطة C والذي ينتقل إلى جهاز مضمن حوالي نصف حجم ثنائي تم إنشاؤه بواسطة رمز C ++ مشابه. أحد الأسباب الرئيسية لذلك هو دعم الاستثناءات.
الاستثناءات هي أداة رائعة تمت إضافتها بواسطة C ++ عبر C ، وإذا لم يتم تشغيلها وتنفيذها بذكاء ، فلن يكون لها عمليا أي وقت تنفيذ (ولكن على حساب زيادة حجم الكود).
دعونا نرى مثالاً في C ++:
// Class A declaration. Methods defined somewhere else; class A { public: A(); // Constructor ~A(); // Destructor (called when the object goes out of scope or is deleted) void myMethod(); // Just a method }; // Class B declaration. Methods defined somewhere else; class B { public: B(); // Constructor ~B(); // Destructor void myMethod(); // Just a method }; // Class C declaration. Methods defined somewhere else; class C { public: C(); // Constructor ~C(); // Destructor void myMethod(); // Just a method }; void myFunction() { A a; // Constructor aA() called. (Checkpoint 1) { B b; // Constructor bB() called. (Checkpoint 2) b.myMethod(); // (Checkpoint 3) } // b.~B() destructor called. (Checkpoint 4) { C c; // Constructor cC() called. (Checkpoint 5) c.myMethod(); // (Checkpoint 6) } // c.~C() destructor called. (Checkpoint 7) a.myMethod(); // (Checkpoint 8) } // a.~A() destructor called. (Checkpoint 9)
يتم تحديد طرق الفئات A
و B
و C
في مكان آخر (على سبيل المثال في ملفات أخرى). لذلك لا يستطيع المترجم تحليلها ولا يمكنه معرفة ما إذا كان سيطرح استثناءات. لذلك يجب أن تستعد للتعامل مع الاستثناءات التي تم إلقاؤها من أي من المنشئين أو المدمرات أو استدعاءات الطريقة الأخرى. لا يجب أن تطرح أدوات التدمير (ممارسة سيئة للغاية) ، ولكن يمكن للمستخدم أن يرمي على أي حال ، أو يمكن أن يرمي بشكل غير مباشر عن طريق استدعاء وظيفة أو طريقة (صراحة أو ضمنيًا) تطرح استثناءً.
إذا ألقى أي من الاستدعاءات في myFunction
استثناءً ، فيجب أن تكون آلية فك المكدس قادرة على استدعاء جميع المواد المدمرة للكائنات التي تم إنشاؤها بالفعل. سيستخدم تنفيذ واحد لآلية فك المكدس عنوان المرسل لآخر مكالمة من هذه الوظيفة للتحقق من "رقم نقطة التفتيش" للمكالمة التي أطلقت الاستثناء (هذا هو التفسير البسيط). يقوم بذلك عن طريق الاستفادة من وظيفة مساعدة مولدة تلقائيًا (نوع من جدول البحث) التي سيتم استخدامها لفك المكدس في حالة طرح استثناء من جسم تلك الوظيفة ، والذي سيكون مشابهًا لما يلي:
// Possible autogenerated function void autogeneratedStackUnwindingFor_myFunction(int checkpoint) { switch (checkpoint) { // case 1 and 9: do nothing; case 3: b.~B(); goto destroyA; // jumps to location of destroyA label case 6: c.~C(); // also goes to destroyA as that is the next line destroyA: // label case 2: case 4: case 5: case 7: case 8: a.~A(); } }
إذا تم طرح الاستثناء من نقطتي التفتيش 1 و 9 ، فلا يوجد كائن يحتاج إلى تدمير. بالنسبة إلى نقطة التفتيش 3 ، يجب تدمير b
و a
. بالنسبة إلى نقطة التفتيش 6 ، يجب تدمير c
و a
. في جميع الأحوال يجب احترام أمر التدمير. بالنسبة لنقاط التفتيش 2 و 4 و 5 و 7 و 8 ، يجب تدمير a
فقط.
تضيف هذه الوظيفة المساعدة حجمًا إلى الكود. هذا جزء من المساحة الإضافية التي تضيفها C ++ إلى C. لا تستطيع العديد من التطبيقات المضمنة تحمل هذه المساحة الإضافية. لذلك ، غالبًا ما تحتوي برامج التحويل البرمجي لـ C ++ للأنظمة المضمنة على علامة لتعطيل الاستثناءات. تعطيل الاستثناءات في C ++ ليس مجانيًا ، لأن مكتبة النماذج القياسية تعتمد بشكل كبير على الاستثناءات للإبلاغ عن الأخطاء. يتطلب استخدام هذا النظام المعدل ، بدون استثناءات ، مزيدًا من التدريب لمطوري C ++ لاكتشاف المشكلات المحتملة أو العثور على الأخطاء.
ونحن نتحدث عن C ++ ، وهي لغة مبدأها: "أنت لا تدفع مقابل ما لا تستخدمه". تزداد هذه الزيادة في الحجم الثنائي سوءًا بالنسبة للغات الأخرى التي تضيف عبئًا إضافيًا مع ميزات أخرى مفيدة جدًا ولكن لا يمكن توفيرها بواسطة الأنظمة المضمنة. على الرغم من أن لغة C لا تمنحك استخدام هذه الميزات الإضافية ، إلا أنها تتيح بصمة رمز أكثر إحكاما من اللغات الأخرى.
أسباب لتعلم ج
لغة C ليست لغة صعبة التعلم ، لذا فإن جميع الفوائد من تعلمها ستكون رخيصة جدًا. دعونا نرى بعض هذه الفوائد.
لينغوا فرانكا
كما ذكرنا سابقًا ، تعد لغة C لغة مشتركة للمطورين. تم توفير العديد من تطبيقات الخوارزميات الجديدة في الكتب أو على الإنترنت أولاً (أو فقط) في لغة C بواسطة مؤلفيها. هذا يعطي أقصى قدر ممكن من قابلية التنفيذ. لقد رأيت مبرمجين يكافحون على الإنترنت لإعادة كتابة خوارزمية C إلى لغات برمجة أخرى لأنه أو لأنها لم تكن تعرف المفاهيم الأساسية جدًا لـ C.
اعلم أن لغة C هي لغة قديمة وواسعة الانتشار ، لذا يمكنك العثور على جميع أنواع الخوارزميات المكتوبة بلغة C حول الويب. لذلك من المحتمل جدًا أن تستفيد من معرفة هذه اللغة.
افهم الآلة (فكر في سي)
عندما نناقش سلوك أجزاء معينة من التعليمات البرمجية ، أو ميزات معينة للغات أخرى ، مع الزملاء ، ينتهي بنا الأمر إلى "التحدث بلغة C:" هل هذا الجزء يمرر "مؤشر" إلى الكائن أم ينسخ الكائن بأكمله؟ هل يمكن أن يحدث أي "طاقم عمل" هنا؟ وما إلى ذلك وهلم جرا.
نادرًا ما نناقش (أو نفكر) في تعليمات التجميع التي ينفذها جزء من الكود عند تحليل سلوك جزء من كود لغة عالية المستوى. بدلاً من ذلك ، عند مناقشة ما تفعله الآلة ، نتحدث (أو نفكر) بوضوح تام في C.
علاوة على ذلك ، إذا كنت لا تستطيع التوقف والتفكير بهذه الطريقة فيما تفعله ، فقد ينتهي بك الأمر بالبرمجة بنوع من الخرافات حول كيفية إنجاز الأشياء (بطريقة سحرية).
العمل على العديد من المشاريع المثيرة للاهتمام
يتم تنفيذ العديد من المشاريع المثيرة للاهتمام ، من خوادم قواعد البيانات الكبيرة أو نواة نظام التشغيل ، إلى التطبيقات المدمجة الصغيرة التي يمكنك حتى القيام بها في المنزل من أجل رضاك الشخصي والمتعة ، في C. لا يوجد سبب للتوقف عن فعل الأشياء التي قد تحبها لسبب واحد أنك لا تعرف لغة برمجة قديمة وصغيرة ، لكنها قوية ومثبتة زمنياً مثل C.
خاتمة
لا يبدو أن لغة البرمجة C لها تاريخ انتهاء صلاحية. إنه قريب من الأجهزة ، وقابلية كبيرة للنقل والاستخدام الحتمي للموارد يجعله مثاليًا لتطوير المستوى المنخفض لأشياء مثل نواة نظام التشغيل والبرامج المضمنة. إن تنوعها وكفاءتها وأدائها الجيد يجعلها خيارًا ممتازًا لبرامج معالجة البيانات عالية التعقيد ، مثل قواعد البيانات أو الرسوم المتحركة ثلاثية الأبعاد. حقيقة أن العديد من لغات البرمجة اليوم أفضل من لغة C للاستخدام المقصود لا تعني أنها تتفوق على C في جميع المجالات. لا يزال C غير مسبوق عندما يكون الأداء هو الأولوية.
يعمل العالم على الأجهزة التي تعمل بالطاقة C. نستخدم هذه الأجهزة كل يوم سواء أدركنا ذلك أم لا. C هو الماضي والحاضر ، وبقدر ما يمكننا أن نرى ، لا يزال المستقبل للعديد من مجالات البرمجيات.