C# للبرمجة النظامية: عندما يلتقي المستوى العالي مع العتاد المنخفض
\n\nعندما تسمع عبارة "البرمجة النظامية"، عادةً ما تتبادر إلى الذهن صور لخبراء ملتحين يكتبون بلغة C أو لغة التجميع، مع محطات طرفية مليئة بنص أخضر. أما C# فهي "لتطبيقات الأعمال"، "لـ Windows Forms" و"لمن لا يريدون عناء التعامل مع المؤشرات". مفاجأة: هذه أسطورة.
\n\nفي الواقع، C# هي سكين سويسري لمبرمج الأنظمة الذي يريد الكتابة بسرعة وأمان، ولكن عند الضرورة - الدخول إلى قلب الذاكرة غير المُدارة. في هذه المقالة، سنشرح كيف تساعد C# في حل المهام النظامية الحقيقية: من التعامل مع العمليات إلى الوصول المباشر للذاكرة عبر WinAPI. ونعم، ستكون هناك أمثلة كود - لا غنى عنها.
لماذا C# ليست مجرد "لعبة أعمال"؟
\n\nالبرمجة النظامية باستخدام C# ليست تناقضاً. منصة .NET (خاصة .NET 5+) تمنح المطور مزيجاً فريداً: أداء قريب من الكود الأصلي، وسهولة لغة عالية المستوى. يمكنك كتابة برامج تشغيل، التعامل مع العمليات، تخصيص الذاكرة يدوياً، وفي نفس الوقت لا تفقد صوابك بسبب إدارة الموارد.
\n\nالإمكانيات الرئيسية التي تجعل C# مناسبة للبرمجة النظامية:
\n- \n
- كود Unsafe والمؤشرات — نعم، في C# يمكنك التعامل مع العناوين مباشرة، كما في C++. \n
- P/Invoke — استدعاء أي دوال من المكتبات الأصلية (WinAPI, libc, برامج تشغيل). \n
- Span
و Memory — التعامل الآمن مع كتل الذاكرة المتصلة دون تخصيصات زائدة. \n - Native AOT — الترجمة إلى كود أصلي بدون JIT و CLR. \n
- التفاعل مع C/C++ — تضمين C# في مشاريع نظامية قائمة. \n
إذا كنت تعتقد أن C# مخصصة فقط للويب وقواعد البيانات، فاستعد للدهشة.
\n\nكود Unsafe: اللعب بالنار، ولكن تحت السيطرة
\n\nالكلمة المفتاحية unsafe في C# هي مثل الزر الأحمر في صاروخ نووي. ضغطت عليها - ويمكنك فعل كل شيء: إلغاء الإشارة إلى المؤشرات، التعامل مع الكائنات الثابتة، تخصيص ذاكرة المكدس. لكن المسؤولية مطلقة.
لنفترض أننا بحاجة لنسخ مصفوفة بايت بسرعة، متجاوزين فحوصات الحدود. في الكود الآمن، كنا سنستخدم Array.Copy، ولكن إذا كنا نكتب أداة نظامية للتعامل مع برنامج تشغيل، فكل ميكروثانية لها حسابها.
using System;\n\nunsafe class MemoryCopy\n{\n public static void FastCopy(byte[] source, byte[] dest, int length)\n {\n fixed (byte* pSrc = source, pDst = dest)\n {\n byte* ps = pSrc;\n byte* pd = pDst;\n for (int i = 0; i < length; i++)\n *pd++ = *ps++;\n }\n }\n}\n\nهنا نستخدم fixed "لتثبيت" المصفوفات المُدارة في الذاكرة، حتى لا يقوم جامع القمامة بتحريكها أثناء النسخ. النتيجة - نسخ بسرعة قريبة من memcpy في C. بالطبع، للمهام اليومية هذا مبالغ فيه، ولكن لـ البرمجة النظامية باستخدام C# هو أمر لا غنى عنه.
متى يكون unsafe مبرراً؟
\n- \n
- التعامل مع حزم الشبكات على مستوى البايت الخام. \n
- التفاعل مع العتاد عبر DMA. \n
- تنفيذ مخصصات ذاكرة خاصة. \n
- تحسين أجزاء الكود الحرجة (مثل معالجة الفيديو من الكاميرا). \n
P/Invoke و WinAPI: C# تقرع باب النواة
\n\nالبرمجة النظامية الحقيقية مستحيلة بدون استدعاء الدوال الأصلية. توفر C# لهذا آلية P/Invoke (Platform Invocation Services). هل تريد الحصول على قائمة العمليات، إدارة النوافذ، أو قراءة ذاكرة عملية أخرى؟ تفضل.
\n\nلننظر إلى مثال كلاسيكي - الحصول على قائمة العمليات الجارية عبر دالة WinAPI CreateToolhelp32Snapshot.
using System;\nu