السلام عليكم
يسرني أن أبدأ معكم هذا النقاش الذي يتمحور حول مقارنة الخدمات القياسية و الدوال الجاهزة التي تُوفرها السي مع بقية الخدمات القياسية (و أصر على كلمة "قياسية") الموجودة في معظم لغات البرمجة :) (خصوصاً الجافا)
1. شخصياً, أرى أن لغة السي القياسية غير مرنة في التعامل مع المصوفات الحرفية (النصوص) لأن الإعتماد على نوع بدائي مثل char سيكون مُرهقا جداً.
فمشاكل الترميز (دعم اليونيكود مثلا) و الفيض (الــ OverFlow) لا تزال مطروحة بشكل كبير في السي ..
في الجافا, توجد الفئة String التي تدعم ترميز الــ Unicode بالإضافة إلى حجمها الكبير جداً..
مشكلة الـــ Over لا تقتصر على المصفوفات الحرفية في لغة السي القياسية حيث نجدها تكرر عند التعامل مع الأرقام الضخمة ! أما في الجافا فيوجد الصنف BigInteger الذي بإمكانه تخزين أعداد تحتوي على سطور من الأرقام.
2. في الملفات مثلا, لا توجد طريقة قياسية في لغة السي لمعرفة سبب عدم فتح الملف !
في معيار C ISO, الحل الوحيد لاختبار وجود ملف هو محاولة فتحه:
FILE *fp = fopen("fichier.txt", "r");
if (fp == NULL) {
fputs("Le fichier n’existe pas,\n"
"ou vous n’avez pas les droits necessaires\n"
"ou il est inaccessible en ce moment\n"
, stderr);
} else {
/* ... operation sur le fichier */
fclose(fp);
}مع أن هذه الطريقة ليست سليمة 100% لأنه إذا لم يتم فتح الملف فهذا لا يعني بالضرورة أن الملف غير موجود !, توجد عدة أسباب أخرى :
- قد لا تملك الصلاحيات الضرورية لفتح الملف
- قد لا يمكن الوصول إلى محتوى الملف في تلك اللحظة (ملف مُشفر مثلا)
- قد لا يملك النظام مساحة الذاكرة الكافية لفتح الملف
في نظام DOS/Windows و أنظمة *Nix يمكننا فحص قيمة errno, هل هي مُساوية لـــ ENOENT (no such file or directory).
أما في الجافا فالأمر بسيط جداً, مجرد تحقق بسيط من القيمة المُعادة من طرف الدالة exists و ينتهي الأمر :
File f = new File(msg);
if (f.exists()) System.out.print("found ");
else System.out.print("not found");كذلك, عندما نُحاول معرفة حجم ملف معين في لغة السي القياسية سنجد أن الدالتان stat و fstat التابعتان للمعيار POSIX غير مُدرجتان في معيار ISO.
الحل القياسي الوحيد يكمن في استخدام الدالتين fseek و ftell :
int fsize(const char * fname, long * ptr) {
/* Cette fonction retourne 0 en cas de succes, une valeur differente dans le cas contraire. */
/* La taille du fichier, si elle a pu etre calculee, est retournee dans *ptr */
FILE * f;
int ret = 0;
f = fopen(fname, "rb");
if (f != NULL) {
fseek(f, 0, SEEK_END); /* aller a la fin du fichier */
*ptr = ftell(f); /* lire l'offset de la position courante par rapport au debut du fichier */
fclose(f);
} else
ret = 1;
return ret;
}أما في الجافا فيمكننا استخدام الدالة length الموجودة في الفئة java.io.File هكذا :
long octets = new File("monFichier.txt").length();نفس الشيء في لغة السي القياسية يحدث مع نسخ الملفات, إذ لا توجد دالة جاهزة لفعل هذا الأمر حيث ستضطر إلى كتابة دالة تقرأ الملف ثم تقوم بنسخه في الملف المطلوب هكذا مثلا :
int copier_fichier(char const * const source, char const * const destination) {
FILE* fSrc;
FILE* fDest;
char buffer[512];
int NbLus;
if ((fSrc = fopen(source, "rb")) == NULL) {
return 1;
}
if ((fDest = fopen(destination, "wb")) == NULL) {
fclose(fSrc);
return 2;
}
while ((NbLus = fread(buffer, 1, 512, fSrc)) != 0)
fwrite(buffer, 1, NbLus, fDest);
fclose(fDest);
fclose(fSrc);
return 0;
}أما في الجافا فيمكننا إنشاء كائن من الفئة FileInputStream لقراءة الملف المُراد نسخه و كائن آخر من الفئة FileOutputStream لكتابة بيانات الملف الجديد ثم نُمرر الكائنين السابقين للدالة copy (الموجودة في الفئة IOUtils) حيث تقوم بنسخ محتويات الــ InputStream إلى الــ OutputStream, هكذا :
import org.apache.commons.io.IOUtils;
InputStream input = new FileInputStream("monFichierSource.txt");
OutputStream output = new FileOutputStream("monNouveauFichier.txt");
IOUtils.copy(input, output);في لغة السي القياسية, إذا أردتَ مثلا أن تحذف سطراً في ملف معين فعليك كتابة الدالة بنفسك لأن السي القياسية لا تحتوي على دالة جاهزة لمثل هذا الأمر !
أما في الجافا, فيمكننا قراءة الملف ووضعه داخل Vector ثم نُمرر رقم السطر إلى الدالة removeElementAt و ينتهى الأمر :
public static void main(String args[]) throws IOException {
Vector monVector = new Vector();
File f = new File("monFichier.txt");
BufferedReader B = new BufferedReader(new FileReader(f));
String ligne = B.readLine();
while (ligne != null){
monVector.addElement(ligne);
ligne = B.readLine();
}
monVector.removeElementAt(numeroLigne);
PrintWriter P = new PrintWriter (new FileWriter(f));
for (int i = 0; i < monVector.size(); i++){
P.println(monVector.get(i));
}
P.close();
}3. لغة السي و حتى السي++, لا تمتلك أي منهما مكتبة GUI قياسية و بالتالي إذا أردتَ برمجة الواجهات ستحتاج إلى مغادرة المطار القياسي لــ C/C++ مُتوجها إلى الــ MFC, GTK, QT, VCL أو الــ wxWidgets.
أما في الجافا فتجد مكتوباً في أعلى غرفة الــ GUI : مرحبا بك في عالم الــ Swing/AWT !
هذه الأسباب الثلاثة و غيرها جعلت من لغة السي (أو على الأقل حسب وجهة نظري) تبدو و كأنها فقيرة من ناحية الدوال الضرورية التي تُقدمها و التي من شأنها أن تختصر عمل المبرمج.
ما رأيكم ؟





