مقارنة بين لغة باسكال ولغة سي

تتشابه لغتا البرمجة C وباسكال في تاريخ نشأتهما وتأثيراتهما وأهدافهما. وقد استُخدمت كلتاهما لتصميم (وتجميع) مترجماتهما الخاصة في بداياتهما. ظهر تعريف باسكال الأصلي عام 1969 ، وأول مترجم لها عام 1970. أما النسخة الأولى من لغة C فقد ظهرت عام 1972.

كلتاهما من سلالة لغات ALGOL . قدمت ALGOL دعمًا للغات البرمجة الهيكلية ، حيث تُبنى البرامج من عبارات دخول وخروج مفردة مثل if و while و for و case . تنحدر لغة باسكال مباشرةً من ALGOL W ، مع أنها تشاركت بعض الأفكار الجديدة مع ALGOL 68. أما لغة C، فهي مرتبطة بـ ALGOL بشكل غير مباشر، في الأصل من خلال B و BCPL و CPL ، ولاحقًا من خلال ALGOL 68 (على سبيل المثال في حالة structو union) وأيضًا من خلال باسكال (على سبيل المثال في حالة التعدادات constو typedefوالقيم المنطقية). كما دمجت بعض لهجات باسكال سمات من لغة C.

اللغات الموثقة هنا هي لغة باسكال التي صممها نيكلاوس ويرث ، والتي تم توحيدها وفقًا لمعيار ISO 7185 في عام 1982، ولغة سي التي صممها دينيس ريتشي ، والتي تم توحيدها وفقًا لمعيار C89 في عام 1989. والسبب في ذلك هو أن هاتين النسختين تمثلان النسخة الناضجة من اللغة، بالإضافة إلى تقاربهما الزمني. لم يتم تضمين ميزات معيار ANSI C و C99 (المعياران الأحدث للغة سي)، وميزات التطبيقات اللاحقة للغة باسكال ( مثل Turbo Pascal و Free Pascal )، في هذه المقارنة، على الرغم من التحسينات التي أضافتها هذه التطبيقات من حيث المتانة والوظائف. (انظر على سبيل المثال: مقارنة بين باسكال ودلفي)

بناء الجملة

من الناحية التركيبية ، تُشبه لغة باسكال لغة ALGOL أكثر من لغة C. فهي تحتفظ بالكلمات المفتاحية الإنجليزية حيث تستخدم C علامات الترقيم - على سبيل المثال، تحتوي باسكال على و andو orو modبينما تستخدم C علامات الترقيم و و و على سبيل المثال. ومع ذلك، تُشبه لغة C لغة ALGOL أكثر من باسكال فيما يتعلق بالتصريحات (البسيطة)، إذ تحتفظ بصيغة اسم النوع-اسم المتغير-اسم المتغير . فعلى سبيل المثال، يمكن للغة C قبول التصريحات في بداية أي كتلة، وليس فقط في الكتلة الخارجية للدالة.&&||%

استخدام الفاصلة المنقوطة

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

  • في لغة باسكال، لا يمكن وضع الفاصلة المنقوطة مباشرة قبل الفاصلة else، بينما في لغة سي، فهي إلزامية، إلا إذا تم استخدام عبارة كتلة.
  • لا يشترط وضع فاصلة منقوطة بعد العبارة الأخيرة التي تسبق حرف العطف " endأو" .until

يمكن وضع فاصلة منقوطة زائدة في السطر الأخير قبل كلمة end ، وبالتالي إدراج عبارة فارغة بشكل رسمي .

تعليقات

في الطبعة الأولى من لغة C، يوجد فقط /* block comments */. تمت إضافة C لاحقًا // line comments.

في لغة باسكال، يوجد و .{ block comments }(* block comments *)

المعرفات والكلمات المفتاحية

تختلف لغتا C وباسكال في تفسيرهما للأحرف الكبيرة والصغيرة. لغة C حساسة لحالة الأحرف، بينما لغة باسكال ليست كذلك، لذا MyLabelفإن mylabel`abc` و`abc` اسمان مختلفان في C، لكنهما متطابقان في باسكال. في كلتا اللغتين، تتكون المعرفات من حروف وأرقام، مع قاعدة أن الحرف الأول لا يجوز أن يكون رقمًا. في لغة C، تُحسب الشرطة السفلية كحرف، لذا حتى `abc` اسم صحيح. غالبًا ما تُستخدم الأسماء التي تبدأ بشرطة سفلية لتمييز معرفات النظام الخاصة في لغة C.

تستخدم كل من لغتي C و Pascal الكلمات المفتاحية (كلمات محجوزة لاستخدام اللغة). ومن أمثلتها if و while و const و for و goto ، وهي كلمات مفتاحية مشتركة بين اللغتين. في لغة C، تُعد أسماء الأنواع الأساسية المدمجة كلمات مفتاحية أيضًا (مثل int و char ) أو تركيبات من الكلمات المفتاحية (مثل unsigned char )، بينما في لغة Pascal، تُعد أسماء الأنواع المدمجة مُعرّفات عادية مُعرّفة مسبقًا.

التعريفات والتصريحات والكتل

في لغة باسكال، تبدأ تعريفات الإجراءات الفرعية بالكلمات المفتاحية procedure (بدون إرجاع قيمة) أو function (مع إرجاع قيمة)، بينما تبدأ تعريفات الأنواع بالكلمة المفتاحية type . أما في لغة C، فجميع الإجراءات الفرعية لها functionتعريفات (الإجراءات هي void functions)، وتستخدم تعريفات الأنواع الكلمة المفتاحية type typedef. تستخدم كلتا اللغتين مزيجًا من الكلمات المفتاحية وعلامات الترقيم لتعريف الأنواع المعقدة؛ على سبيل المثال، تُعرَّف المصفوفات بالكلمة المفتاحية array في باسكال وبعلامات الترقيم في C، بينما تُعرَّف التعدادات بالكلمة المفتاحية array enumفي C وبعلامات الترقيم في باسكال.

في الدوال الفرعية في لغة باسكال، تُستخدم العلامتان begin و end لتحديد مجموعة من التعليمات مسبوقة بتصريحات محلية، بينما تستخدم دوال لغة C العلامتين { و } لتحديد مجموعة من التعليمات مسبوقة بتصريحات اختيارية  . تنص لغة C (قبل C99) صراحةً على وجوب ظهور أي تصريحات قبل التعليمات داخل كتلة معينة، ولكنها تسمح بظهور كتل داخل كتل أخرى، وهو ما يُعدّ حلاً بديلاً. أما في باسكال، فمن خلال بنية جسم الدالة الفرعية، تُفرض التصريحات قبل التعليمات. كما تسمح باسكال بتغليف تعريفات الأنواع والدوال - وليس فقط تصريحات المتغيرات - داخل تعريفات الدوال بأي مستوى من العمق.  

تطبيق

تتشابه قواعد اللغتين في الحجم. من منظور التنفيذ، يكمن الاختلاف الرئيسي بينهما في أن تحليل لغة C يتطلب الوصول إلى جدول رموز للأنواع، بينما في لغة باسكال يوجد بنية واحدة فقط، وهي التعيين. على سبيل المثال، X * Y;قد يكون جزء C عبارة عن تعريف Yلكائن من نوع مؤشر إلى X، أو عبارة عن جملة تضرب Xفي Y. في المقابل، فإن جزئي باسكال المقابلين واضحان تمامًا؛ ولا يتطلب التحليل الصحيح جدول رموز.var Y : ^X;Z := X * Y;

أنواع بسيطة

الأعداد الصحيحة

تتطلب لغة باسكال تحديد نوع جميع المتغيرات والدوال بشكل صريح. أما في لغة سي التقليدية، فيمكن حذف اسم النوع في معظم السياقات، ويُفترض ضمنيًا النوع الافتراضي int(الذي يُقابل النوع الافتراضي integerفي باسكال) (مع ذلك، تُعتبر هذه القيم الافتراضية ممارسة سيئة في لغة سي، وغالبًا ما تُنبّه إليها تحذيرات).

تدعم لغة C أحجامًا مختلفة وأنماطًا مُوقّعة وغير مُوقّعة للأعداد الصحيحة باستخدام مُعدِّلات مثل long`int` shortو`int` signedو` unsignedint` و`int` وما إلى ذلك. يختلف المعنى الدقيق لنوع العدد الصحيح الناتج باختلاف الجهاز، ولكن ما يُمكن ضمانه هو long intألا يكون `int` أقصر من ` int` intوألا intيكون `int` أقصر من `int` short int. مع ذلك، في معيار C، توجد أحجام دنيا مُحدَّدة للأنواع تضمن أن يكون ` int` بايتًاchar واحدًا وأن يكون `int` بايتين على الأقل.int

النطاقات الفرعية

في لغة باسكال، يتم تنفيذ نهاية مماثلة عن طريق تعريف نطاق فرعي من الأعداد الصحيحة (يمكن للمترجم بعد ذلك اختيار تخصيص مساحة تخزين أصغر للمتغير المُعلن عنه):

النوع أ = 1 .. 100 ؛ ب = -20 .. 20 ؛ ج = 0 .. 100000 ؛

لا تدعم لغة C ميزة النطاق الفرعي هذه.

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

في لغة C، يجب أولاً ترقية المعاملات إلى حجم النتيجة المطلوبة: تكون النتائج الوسيطة غير مُعرَّفة إذا لم تكن ضمن نطاق المعاملات المُرَقَّاة. إذا كان نطاق النتيجة المطلوبة أكبر من نطاق المعاملات، فإن هذا عادةً ما يُنتج شيفرة بطيئة وغير فعّالة، حتى مع مُصرِّف مُحسِّن جيد. مع ذلك، لا يُطلب من مُصرِّف لغة C أو يُتوقع منه أبدًا التعامل مع النتائج الوسيطة الخارجة عن النطاق: تقع مسؤولية ضمان أن جميع النتائج الوسيطة ضمن نطاق المعاملات على عاتق المُبرمج.

سمحت تطبيقات ما قبل المعيار للغة C بالإضافة إلى Small-C وما إلى ذلك بخلط أنواع الأعداد الصحيحة والمؤشرات بحرية نسبية.

أنواع الشخصيات

في لغة C، نوع الأحرف هو ` charn`، وهو نوع من الأعداد الصحيحة التي لا يزيد طولها عن short int`n`. وبالتالي، فإن التعبيرات مثل `n` 'x' + 1صحيحة تمامًا، وكذلك التصريحات مثل `n` int i = 'i';و`n` char c = 74;.

تتضح طبيعة العدد الصحيح char(بايت واحد) بوضوح من خلال تصريحات مثل

unsigned char uc = 255 ; // الحد المشترك signed char sc = -128 ; // الحد السالب المشترك

يعتمد تحديد ما إذا كان charينبغي اعتبار النوع على أنه افتراضي signedأم unsignedلا على التنفيذ.

في لغة باسكال، تُعتبر الأحرف والأعداد الصحيحة أنواعًا منفصلة. يمكن استخدام دوال المُصرّف المُدمجة ord()لتحويل chr()الأحرف المفردة إلى قيمتها العددية المُقابلة في مجموعة الأحرف المُستخدمة، والعكس صحيح. على سبيل المثال، في الأنظمة التي تستخدم مجموعة أحرف ASCII، ord('1') = 49يكون chr(9)الحرف هو حرف الجدولة (TAB).

أنواع منطقية

في لغة باسكال، يُعتبر النوع المنطقي (boolean) نوعًا مُعدّدًا. القيم الممكنة له هي خطأ (false ) وصواب ( true) ، حيث تكون القيمة الترتيبية لخطأ  =  0 وصواب  =  1. ولتحويله إلى عدد صحيح ، يُستخدم النوع ord .

i := ord ( b ) ;

لا توجد دالة قياسية لتحويل الأعداد الصحيحة إلى قيم منطقية ، ومع ذلك، فإن التحويل بسيط من الناحية العملية:

b := i <> 0 ;

تحتوي لغة C على نوع بيانات منطقي (Booleanbool ) منذ إصدار C23 ، بينما لم يكن لديها نوع بيانات منطقي قبل ذلك. تستخدم لغة C عوامل مقارنة ثنائية القيمة (<، >، ==،  !=، <=، >=) والتي يمكن اعتبارها منطقية بمعنى أنها تعطي دائمًا نتائج إما صفر أو واحد. بما أن جميع الاختبارات (&&، ||،  ?:، if ، while ، إلخ) تُجرى عن طريق التحقق من الصفر، فإن القيمة false تُمثل بالصفر، بينما تُمثل القيمة true بأي قيمة أخرى. هذا واضح في boolنوع البيانات العددية المُعرّف في <stdbool.h>الإصدارات السابقة لـ C23.

عمليات البت

تسمح لغة C باستخدام عوامل التشغيل الثنائية لإجراء عمليات منطقية. يجب توخي الحذر لأن دلالات العمليات تختلف عندما تستخدم المعاملات أكثر من بت واحد لتمثيل قيمة ما.

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

باسكال:

الحالة := الحالة + [ العلامة الثابتة ] ؛ الحالة := الحالة - [ العلامة الثابتة ] ؛ إذا كانت ( العلامة الثابتة في الحالة ) ...

ج:

الحالة |= علامة لاصقة ؛ الحالة &= ~ علامة لاصقة ؛ إذا ( الحالة & علامة لاصقة ) { ...

على الرغم من أنه يمكن اعتبار عمليات البت على الأعداد الصحيحة والعمليات على المجموعات متشابهة إذا تم تنفيذ المجموعات باستخدام البتات، إلا أنه لا يوجد توازي مباشر بين استخداماتها إلا إذا كان التحويل غير القياسي بين الأعداد الصحيحة والمجموعات ممكنًا.

ملاحظة حول التنفيذ

أثناء تقييم التعبير، وفي كلتا اللغتين ، قد يتم تخزين القيمة المنطقية داخليًا كبت واحد، أو بايت واحد، أو كلمة آلة كاملة، أو موضع في الكود المُولّد، أو كرمز حالة في سجل الحالة، اعتمادًا على الجهاز والمترجم والوضع؛ وعادة ما تكون هذه العوامل أكثر أهمية من اللغة التي تم تجميعها.

أنواع البيانات ذات الفاصلة العائمة

تتميز لغة C بنموذج أقل صرامة لأنواع الأعداد العشرية مقارنةً بلغة باسكال. ففي لغة C، يمكن تحويل الأعداد الصحيحة ضمنيًا إلى أعداد عشرية، والعكس صحيح (مع إمكانية التنبيه إلى فقدان الدقة المحتمل). أما في لغة باسكال، فيمكن تحويل الأعداد الصحيحة ضمنيًا إلى أعداد عشرية real، ولكن تحويل الأعداد العشرية realإلى integerأعداد عشرية (حيث قد تُفقد بعض المعلومات) يجب أن يتم صراحةً باستخدام الدالتين ` trunc()f` و`f` round()، اللتين تقومان بتقريب أو حذف الكسر، على التوالي.

أنواع التعداد

تتضمن كل من لغتي C و Pascal أنواع التعداد. مثال بلغة Pascal:

نوع اللون = ( أحمر ، أخضر ، أزرق ) ؛ متغير أ : لون ؛

مثال على مكيف الهواء:

enum Color { RED , GREEN , BLUE };enum Color a = RED ;

يختلف سلوك أنواع البيانات في اللغتين اختلافًا كبيرًا. في لغة باسكال، تكون التعدادات ترتيبية ويتم تحليلها باستخدام ` arguments` ord()، وتختلف الدالتان `arguments` و`arguments` عن بنية `arguments`. أما في لغة C، فتُنفذ التعدادات كمصفوفات، ويصبح `arguments` مرادفًا للأرقام 0 و1 و2، ولا يوجد ما يمنع إسناد قيمة خارج هذا النطاق إلى المتغير `arguments` . علاوة على ذلك، تُحظر عمليات مثل `arguments` في باسكال؛ وبدلاً من ذلك، يُستخدم `arguments` . في لغة C، يمكن تحويل التعدادات بحرية من وإلى الأعداد الصحيحة، ولكن في باسكال، يجب استخدام الدالة ` arguments` للتحويل من أنواع التعدادات إلى أعداد صحيحة. لا يمكن تحويل الأعداد الصحيحة إلى أنواع تعدادات، ولكن يمكن استخدام أنواع التعدادات في عبارات قد تستخدم أعدادًا صحيحة.succ()pred()arrayREDGREENBLUEaa = a + 1;a := succ(a);ord()

for a := red to blue do

الأنواع المهيكلة

أنواع المصفوفات

تسمح كل من لغتي C و Pascal بإنشاء مصفوفات من أنواع معقدة أخرى، بما في ذلك المصفوفات الأخرى. ومع ذلك، ينتهي التشابه بين اللغتين عند هذا الحد. تُعرَّف مصفوفات C ببساطة بنوع أساسي وعدد العناصر.

int a [ SIZE ];

ويتم فهرستها دائمًا من 0أعلى إلى SIZE - 1(أي modulo SIZE).

في لغة باسكال، غالبًا ما يتم تحديد نطاق المؤشرات بواسطة نطاق فرعي (كما هو موضح في قسم الأنواع البسيطة أعلاه). العناصر العشرة لـ

var a : array [ 0 .. 9 ] of integer ;

سيتم فهرسة العناصر من 0 إلى 9 (كما هو الحال في لغة C). يمكن أن تكون فهارس المصفوفة من أي نوع بيانات ترتيبي ، وليس فقط نطاقات.

نوع TColor = ( أحمر ، أخضر ، أزرق ) ؛ (* تعداد *) RGB = مصفوفة [ TColor ] من 0 .. 255 ؛var picture : array [ 1 .. 640 , 1 .. 480 ] of RGBلوحة فار : صفيف [ بايت ، 0 .. 2 ] من البايت

يتم تعريف السلاسل المكونة من n > 1 حرفًا على أنها مصفوفات معبأة بنطاق 1..n.

المصفوفات والمؤشرات

في تعابير لغة C، يُعامل المعرّف الذي يُمثّل مصفوفة كمؤشر ثابت إلى العنصر الأول من المصفوفة، وبالتالي، بالنظر إلى التصريحات int a[10]والتخصيص، يكون int *p;الإسناد p = aصحيحًا ويجعل p و a يشيران إلى نفس المصفوفة. ومع ذلك، بما أن المعرّف aيُمثّل عنوانًا ثابتًا ، a = pفإن الإسناد غير صحيح.

على الرغم من أن المصفوفات في لغة C ثابتة، إلا أن المؤشرات إليها قابلة للتبديل. تتيح هذه المرونة للغة C التعامل مع أي مصفوفة مهما كان طولها باستخدام نفس الشيفرة. كما أنها تُلقي على عاتق المبرمج مسؤولية عدم الكتابة خارج نطاق المصفوفة المُخصصة، إذ لا توجد أي آليات تحقق مُدمجة في اللغة.

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

تتيح لغة C إمكانية تهيئة مصفوفات ذات أطوال مختلفة. sizeofويمكن استخدام المعامل `size` للحصول على حجم مصفوفة مُهيأة مسبقًا في كود C. على سبيل المثال، في الكود التالي، يتم تعديل فهرس إنهاء الحلقة تلقائيًا في حال تغيير قائمة السلاسل النصية.

#include <stdio.h>static char * wordlist [] = { "print" , "out" , "the" , "text" , "message" }; static int listSize = sizeof ( wordlist ) / sizeof ( wordlist [ 0 ]);for ( int i = 0 ; i < listSize ; i ++ ) { printf ( wordlist [ i ]); }for ( int i = listSize - 1 ; i >= 0 ; i-- ) { printf ( wordlist [ i ]) ; }

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

const minlist = 1 ; maxlist = 5 ; maxword = 7 ;نوع قائمة النطاق = القائمة الدنيا .. القائمة القصوى ؛ نطاق الكلمات = 1 .. الكلمة القصوى ؛ الكلمة = محتويات السجل : مصفوفة مضغوطة [ نطاق الكلمات ] من الأحرف ؛ الطول : نهاية نطاق الكلمات ؛ قائمة الكلمات = مصفوفة [ نطاق القائمة ] من الكلمات ؛ متغير i : عدد صحيح ؛ الكلمات : قائمة الكلمات ؛إجراء إنشاء قائمة ( متغير w : قائمة الكلمات ) ؛ ابدأ w [ 1 ] .contents := ' print' ؛ w [ 1 ] .length : = 5 ؛ w [ 2 ] .contents := ' out' ؛ w [ 2 ] .length : = 3 ؛ w [ 3 ] .contents := 'the' ؛ w [ 3 ] .length : = 3 ؛ w [ 4 ] .contents := 'text' ؛ w [ 4 ] .length : = 4 ؛ w [ 5 ] .contents : = ' message ' ؛ w [ 5 ] .length : = 7 ؛ نهاية ؛ابدأ إنشاء قائمة ( الكلمات ) ؛ من أجل i := القائمة الدنيا إلى القائمة القصوى ، مع الكلمات [ i ] ، اكتب سطرًا ( المحتويات : الطول ) ؛ من أجل i := القائمة القصوى إلى القائمة الدنيا، مع الكلمات [ i ] ، اكتب سطرًا ( المحتويات : الطول ) نهاية .

الأوتار

في كلتا اللغتين، السلسلة عبارة عن مصفوفة بدائية من الأحرف.

في لغة باسكال، يكون النص الحرفي ذو الطول n متوافقًا مع النوع n packed array [1..n] of char. أما في لغة سي، فالنص يكون عمومًا من النوع n char[n].

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

تُعتبر السلاسل النصية في لغة C منتهية بحرف فارغ ؛ أي أن الحرف الفارغ في نهاية السلسلة يُستخدم كعلامة نهاية السلسلة :

// السلسلة s منتهية بـ null const char * s = "the rain in Spain" ;

يجب الحفاظ على إنهاء السلسلة يدويًا لمتغيرات السلسلة المخزنة في المصفوفات (غالبًا ما يتم التعامل مع هذا جزئيًا بواسطة إجراءات المكتبة).

تفتقر لغة C إلى خاصية تعيين السلاسل أو المصفوفات المدمجة، لذلك لا يتم نقل السلسلة إلى p، بل يتم جعل p يشير إلى السلسلة الثابتة في الذاكرة.

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

أشار مطور نظام FreeBSD، بول هينينغ كامب ، في مقال له في مجلة ACM Queue ، إلى انتصار السلاسل النصية المنتهية بـ null على السلاسل النصية التي تبدأ بـ length على أنه "أغلى خطأ في بايت واحد" على الإطلاق. [ 1 ]

أنواع السجلات

يمكن لكل من لغتي C و Pascal تعريف أنواع " السجلات ". في لغة C، تُسمى هذه الأنواع "هياكل".

struct A { int b ; char c ; };
النوع أ = سجل ب : عدد صحيح ؛ ج : حرف ؛ نهاية ؛

في لغة باسكال، يمكننا استخدام الجملة " with name_of_record do" لاستخدام حقول ذلك السجل مباشرةً، كمتغيرات محلية، بدلاً من كتابة name_of_record . name_of_field . إليك مثال:

نوع r = سجل s : سلسلة نصية ؛ c : حرف ؛ نهاية ؛ متغير r1 : r ؛ ابدأ مع r1 do ابدأ s := 'foo' ؛ c := 'b' نهاية نهاية ؛

لا توجد ميزة مكافئة لـ " with" في لغة C.

في لغة C، يمكن تحديد طول البتات الدقيق للحقل:

struct A { unsigned int b : 3 ; unsigned int c : 1 ; };

يعتمد مقدار التخزين المستخدم على خصائص النظام المستهدف (مثل محاذاة الكلمات).

تتوفر هذه الميزة في لغة باسكال باستخدام بنية النطاق الفرعي (3 بتات تعطي نطاقًا من 0 إلى 7) بالاقتران مع الكلمة المفتاحية packed :

النوع أ = سجل مضغوط ب : 0 .. 7 ؛ ج : 0 .. 1 ؛ نهاية ؛

تدعم كل من لغتي C و Pascal السجلات التي يمكن أن تتضمن حقولاً مختلفة متداخلة مع بعضها البعض:

اتحاد A { int a ; float b ; };
نوع أ = سجل حالة منطقية من خطأ : ( أ : عدد صحيح ) ؛ صحيح : ( ب : عدد حقيقي ) نهاية ؛

يُمكن لكلا معالجي اللغة تخصيص مساحة كافية لهذه السجلات لاحتواء أكبر نوع في الاتحاد/السجل. في لغة باسكال، تُسمى هذه البنى سجلات متغيرة ، ويجب عدم الخلط بينها وبين نوع البيانات Variant المُعرّف في لغة فري باسكال.

يتمثل الاختلاف الأكبر بين لغتي C و Pascal في أن Pascal تدعم الاستخدام الصريح لـ "حقل العلامات" لمعالج اللغة لتحديد ما إذا كان يتم الوصول إلى المكون الصحيح لسجل المتغير:

نوع a = سجل حالة q : منطقي من خطأ : ( a : عدد صحيح ) ؛ صحيح : ( b : عدد حقيقي ) نهاية ؛

في هذه الحالة، يجب تعيين حقل الوسم q إلى الحالة الصحيحة للوصول إلى الأجزاء المناسبة من السجل.

نصائح

في لغة C، يمكن جعل المؤشرات تشير إلى معظم كيانات البرنامج، بما في ذلك الكائنات أو الدوال:

int a ; int * b ; int ( * compare )( int c , int d ); int myCompare ( int c , int d ); b = &a a ; compare = & myCompare ;

في لغة C، بما أن المصفوفات والمؤشرات متقاربة في التكافؤ، فإن ما يلي هو نفسه:

a = b [ 5 ]; a = * ( b + 5 ); a = * ( 5 + b ); a = 5 [ b ]; // صحيح من الناحية الفنية، ولكنه قد يكون غير مألوف

وبالتالي، تُستخدم المؤشرات في لغة C غالبًا كطريقة أخرى للوصول إلى المصفوفات.

لإنشاء بيانات ديناميكية، تُستخدم وظائف المكتبة malloc()للحصول free()على كتل البيانات الديناميكية وتحريرها. لذا، فإن تخصيص الذاكرة الديناميكي غير مُدمج في معالج اللغة. يُعد هذا الأمر بالغ الأهمية عند استخدام لغة C في نواة أنظمة التشغيل أو الأنظمة المُدمجة، حيث أن هذه الأمور تعتمد بشكل كبير على النظام الأساسي (وليس فقط على بنية النظام)، مما يتطلب تغيير مُترجم لغة C لكل نظام أساسي (أو نظام تشغيل) يُستخدم عليه.

تحتوي لغة باسكال على نفس نوع المؤشرات الموجودة في لغة سي، ولكن من خلال ^عامل الإشارة بدلاً من عامل الإشارة في *لغة سي. يرتبط كل مؤشر بعنصر بيانات ديناميكي واحد، ولا يمكن نقله إلا عن طريق التعيين:

النوع أ = ^ عدد صحيح ؛var b , c : a ;جديد ( ب ) ؛ ج := ب ؛

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

تعابير الوجه

مستويات الأولوية

تختلف اللغات اختلافاً كبيراً عندما يتعلق الأمر بتقييم التعبيرات، ولكنها في المجمل قابلة للمقارنة.

باسكال

  1. النفي المنطقي:not
  2. الضرب:* / div mod and
  3. مادة مضافة:+ - or
  4. العلاقات:= <> < > <= >= in

ج

  1. لاحقة أحادية:[] () . -> ++ --
  2. البادئة الأحادية:& * + - ! ~ ++ -- (type) sizeof
  3. الضرب:* / %
  4. مادة مضافة:+ -
  5. يحول:<< >>
  6. العلاقات:< > <= >=
  7. المساواة:== !=
  8. عملية AND الثنائية:&
  9. عملية XOR الثنائية:^
  10. عملية أو بتية:|
  11. منطقي و:&&
  12. أو المنطقي:||
  13. شرطي:? :
  14. تكليف:= += -= *= /= %= <<= >>= &= ^= |=
  15. فاصلة :,

الكتابة

تؤدي معظم المعاملات في لغة باسكال وظائف متعددة، فعلى سبيل المثال، يمكن استخدام علامة الطرح للنفي أو الطرح أو الفرق بين المجموعات (بحسب نوع البيانات والسياق النحوي)، >=ويمكن استخدام المعامل لمقارنة الأرقام أو السلاسل النصية أو المجموعات، وهكذا. أما لغة سي فتستخدم رموز معاملات مخصصة على نطاق أوسع.

اختبارات التخصيص والمساواة

تستخدم اللغتان مُعاملات مختلفة للتخصيص. تستخدم باسكال، مثل لغة ALGOL ، مُعامل المساواة الرياضي =لاختبار المساواة والرمز :=للتخصيص، بينما تستخدم لغة C، مثل لغة B ، مُعامل المساواة الرياضي للتخصيص. في لغة C (وB)، تم اختيار ==رمز FORTRAN لاختبار المساواة.

من الأخطاء الشائعة في لغة C، سواءً بسبب قلة الخبرة أو خطأ كتابي بسيط، وضع تعابير الإسناد داخل عبارات شرطية مثل `$` . سيتم تنفيذ الكود الموجود بين قوسين معقوفين دائمًا لأن تعبير الإسناد يحمل القيمة 10، وهي قيمة غير صفرية، وبالتالي تُعتبر "صحيحة" في لغة C؛ ويعود ذلك جزئيًا إلى أن لغة C (وALGOL) تسمح بإسناد قيم متعددة بهذا الشكل، وهو ما لا تدعمه لغة باسكال. لاحظ أيضًا أن قيمة `$` الآن هي ` $`، مما قد يؤثر على الكود التالي. تحاول مُجمِّعات لغة C الحديثة اكتشاف هذه الحالات وتنبيه المستخدم، مطالبةً إياه باستخدام صيغة أقل غموضًا مثل `$` .if(a=10){...}a = 10a = b = c = 10;a10if((a=10)!=0){...}

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

ومن الجدير بالذكر أن التعبير الشرطي في لغة ALGOL بالشكل له مكافئ في لغة C ( المشغل الثلاثي من CPL ) ولكن ليس في لغة Pascal، والتي ستستخدم .z:=ifa>bthenaelseb;ifa>bthenz:=aelsez:=b;

مشاكل التنفيذ

عندما صمم نيكلاوس ويرث لغة باسكال، كان الهدف هو تقليل عدد مستويات الأسبقية (لتقليل عدد إجراءات التحليل، في نهاية المطاف). لذا، تُعامل معاملات OR و XOR تمامًا مثل عملية الجمع (Addop) وتُعالج على مستوى التعبير الرياضي. وبالمثل، تُعامل عملية AND مثل عملية الضرب (Mulop) وتُعالج على مستوى الطرفية (Term). مستويات الأسبقية هي

مستوىعنصر بناء الجملةالمشغل
0عاملحرفي، متغير
1العامل الموقّعالطرح الأحادي، لا
2شرط*، /، و
3تعبير+، -، أو

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

 x + (y وليس z) / 3 

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

اتبع مؤلفو لغة C نهجًا معاكسًا تمامًا: فهم يعاملون المعاملات على أنها مختلفة، وفي الواقع، يوجد في لغة C ما لا يقل عن 15 مستوى. وذلك لأن لغة C تحتوي أيضًا على المعاملات '=' و'+=' وما شابهها، مثل '<<' و'>>' و'++' و'--'، إلخ. على الرغم من أن المعاملات الحسابية والمنطقية في لغة C تُعامل بشكل منفصل، إلا أن المتغيرات لا تُعامل كذلك: إذ يمكن إجراء اختبار منطقي على أي قيمة عددية صحيحة.

الروابط المنطقية

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

في لغة C، يعد الاعتماد على ترتيب التقييم المنطقي قانونيًا تمامًا، وغالبًا ما يتم استخدامه بشكل منهجي باستخدام عوامل &&التشغيل ||و جنبًا إلى جنب مع عوامل التشغيل مثل ++، +=، وعامل الفاصلة، وما إلى ذلك. وبالتالي، تعمل عوامل التشغيل &&و ||كمجموعات من عوامل التشغيل المنطقية والعبارات الشرطية .

يُعتبر تقييم تعبير الدائرة القصيرة ميزة شائعة للغة C بسبب "مشكلة التقييم":

var i : عدد صحيح ؛ a : مصفوفة مضغوطة [ 1 .. 10 ] من نوع char ؛ ... i := 1 ؛ while ( i <= 10 ) and ( a [ i ] <> 'x' ) do i := i + 1 ؛ ...

هذا البحث الذي يبدو بسيطًا يُشكّل إشكالية في لغة باسكال، لأنّ الوصول إلى المصفوفة a[i] سيكون غير صالح عندما تكون قيمة i تساوي 11. هناك أكثر من طريقة لتجنّب هذه المشكلة. يُقدّم المثال التالي متغيرًا منطقيًا يُشير إلى ما إذا كان الحرف المطلوب قد عُثر عليه أم لا.

const strlen = 10 ; var i : integer ; a : packed array [ 1..strlen ] of char ; found : boolean ; ... i := 1 ; found := false ; while not found and ( i < = strlen ) do if ( a [ i ] = 'x' ) then found := true else i : = i + 1 ; ...

يستخدم المثال التالي عبارة تكرار بدلاً من ذلك:

const strlen = 10 ; var i : integer ; a : packed array [ 1..strlen ] of char ; found : boolean ; ... i := 1 ; repeat found := a [ i ] = ' x ' ; if not found then inc ( i ) ; until found or ( i > strlen ) ; ...

هياكل التحكم

البيانات المتعلقة بهياكل مراقبة المباني متشابهة ولكنها ليست متطابقة.

باسكالج
ifcondthenstmtelsestmtif (cond) stmtelsestmt
whileconddostmtwhile (cond) stmt
repeatstmtuntilconddostmtwhile (cond);
forid := exprtoexprdostmtوforid := exprdowntoexprdostmtfor (expr; cond; expr) stmt
caseexprof    expr:stmt;    ...    expr:stmt;endswitch (expr) {    caseexpr:stmt;    ...    caseexpr:stmt;    default:stmt}

تُترك القيمة النهائية لـ id، وهو متغير التحكم، غير محددة عند الخروج العادي من عبارة for في لغة باسكال.

لا يوجد في لغة باسكال ما يُعادل كلمة "default" . لذا، يتعين على مبرمجي باسكال حماية عبارات الحالة بتعبير مثل: if expr not in [A..B] then default-case . في أغلب الأحيان، سيتم تنفيذ عبارة حالة واحدة فقط.

تحتوي لغة C على ما يُسمى بعبارات الخروج المبكر break و continue . وهي ليست إلزامية، وإذا تم حذفها، فقد يؤدي ذلك إلى تنفيذ أكثر من عبارة case واحدة.

تحتوي كل من لغتي C وباسكال على عبارة goto . مع ذلك، ونظرًا لأن باسكال تدعم الإجراءات/الدوال المتداخلة، يُمكن الانتقال من إجراء أو دالة داخلية إلى الإجراء أو الدالة الحاوية لها؛ وقد شاع استخدام هذه الطريقة لتنفيذ استعادة الأخطاء. تتمتع لغة C بهذه الإمكانية عبر دالتي setjmp و longjmp في معيار ANSI C. وهذا مكافئ، ولكنه أقل أمانًا، لأنه يخزن معلومات خاصة بالبرنامج، مثل عناوين الانتقال وإطارات المكدس، في بنية بيانات يُمكن للمبرمج الوصول إليها.

الوظائف والإجراءات

تُسمى إجراءات باسكال التي تُرجع قيمةً بالدوال، أما الإجراءات التي لا تُرجع قيمةً فتُسمى بالإجراءات. تُسمى جميع الإجراءات في لغة C بالدوال، وتُعرّف دوال C التي لا تُرجع قيمةً بنوع إرجاع void .

تعتبر إجراءات باسكال مكافئة لوظائف C "void"، ووظائف باسكال مكافئة لوظائف C التي تُرجع قيمة.

التصريحان التاليان في لغة C:

دالة عددية f ( عدد صحيح x ، عدد صحيح y دالة فارغة k ( عدد صحيح q 

تُعادل هذه التصريحات ما يلي في لغة باسكال:

دالة f ( x , y : عدد صحيح ) : عدد صحيح ; إجراء k ( q : عدد صحيح ) ;

لا يمكن استخدام دوال باسكال إلا في تعبير، في حين أن دالة C التي تُرجع قيمة يمكن استدعاؤها بنفس طريقة استدعاء دالة "void" وتجاهل قيمة الإرجاع الخاصة بها.

تحتوي لغة باسكال على نوعين مختلفين من المعاملات: تمرير القيمة، وتمرير المرجع (VAR). في كلتا الحالتين، يُستخدم اسم المتغير عند الاستدعاء (لا حاجة إلى عامل العنوان).

دالة f ( z : عدد صحيح ; var k : عدد صحيح ) : عدد صحيح ; // تقبل الدالة عددين صحيحين، أحدهما بالقيمة والآخر بالمرجع Begin z := 1 ; // لن يتم تعديل المتغير الخارجي u، ولكن سيتم تعديل القيمة المحلية في نطاق الدالة k := 1 ; // سيتم تعديل المتغير الخارجي t لأنه تم تمريره بالمرجع // حتى هذه النقطة، z موجود ويساوي 1 End ;x := f ( u , t ) ; // يتم تمرير المتغيرين u و t إلى الاستدعاء: قيمة u ومرجع إلى t

في لغة C، تُمرَّر جميع المعاملات بالقيمة، ولكن يمكن محاكاة التمرير بالمرجع باستخدام المؤشرات. المقطع التالي مشابه لمقطع باسكال المذكور أعلاه:

// تقبل الدالة عددًا صحيحًا (كقيمة) ومؤشرًا إلى عدد صحيح (أيضًا كقيمة) كمعاملات int f ( int z , int * k ) { z = 1 ; // كما في لغة باسكال، يتم تعديل القيمة المحلية ولكن لن يتم تعديل المتغير الخارجي u * k = 1 ; // سيتم تعديل المتغير المشار إليه بواسطة k (مثل t) // حتى هذه النقطة، z موجود ويساوي 1 }x = f ( u , & t ); // يتم تمرير قيمة u وعنوان المتغير t (أو قيمته) إلى الاستدعاء

يُعدّ أحد أهم الفروقات بين لغتي C و Pascal طريقة معالجة المعاملات على المكدس أثناء استدعاء روتين فرعي  : يُطلق على هذا اسم اصطلاح الاستدعاء  . في لغة Pascal، تُضاف المعاملات إلى المكدس من اليسار إلى اليمين، بينما في لغة C، يُضاف المعاملات إلى المكدس من اليمين إلى اليسار.

يتم استدعاء الإجراء بنمط باسكال باستخدام  :

  • يقوم المستدعي بدفع المعاملات إلى المكدس بترتيب من اليسار إلى اليمين (عكس __cdecl )
  • استدعاء الدالة
  • يتم تنظيف المكدس بواسطة المستدعى
مثال على استدعاء على نمط باسكال. ملاحظة: __stdcall تدفع الوسائط بترتيب عكسي. دفع الوسيط 1، دفع الوسيط 2، دفع الوسيط 3، استدعاء الدالة . لا يوجد تنظيف للمكدس عند العودة: الدالة المستدعاة تقوم بذلك.

تتمثل ميزة استدعاء PASCAL على STDCALL في أن الكود أصغر قليلاً، على الرغم من أن تأثير الحجم لا يظهر إلا في البرامج الكبيرة، وأن التكرار يعمل بشكل أسرع.

تسمح لغة C للدوال بقبول عدد متغير من المعاملات، والمعروفة باسم الدوال المتغيرة المعاملات ، باستخدام آلية معقدة من ، va_list ap;مع توفر محدود للأنواع (مثال : لا يوجد شيء لـ ).va_start(ap, count);va_arg(ap, type); bool

int f ( int a , ...);f ( 1 , 2 , 3 , 4 , 5 );

تستخدم الدالة f()مجموعة خاصة من الدوال ( varargs) التي تسمح لها بالوصول إلى كل معلمة على حدة.

تحتوي لغتا باسكال وسي أيضًا على بعض وظائف الإدخال/الإخراج المتغيرة، على سبيل المثال WriteLn()و printf().

تسمح لغة باسكال بتداخل الإجراءات والدوال . وهذا مفيد للسماح باستخدام متغيرات محلية لمجموعة من الإجراءات، وليست عامة. تفتقر لغة سي إلى هذه الميزة، ولا يمكن تحديد نطاق المتغيرات أو الدوال إلا لوحدة نمطية مُجمَّعة، حيث تكون المتغيرات أو الدوال مُعرَّفة كمتغيرات ثابتة ( static) .

تسمح لغة C باستدعاء الدوال بشكل غير مباشر من خلال مؤشر دالة . في المثال التالي، تكون العبارة (*cmpar)(s1, s2)مكافئة لما يلي strcmp(s1, s2):

#include <string.h>int ( * cmpar )( const char * a , const char * b ); const char * s1 = "hello" ; const char * s2 = "world" ;cmpar = & strcmp ; b = ( * cmpar )( s1 , s2 );

في لغة باسكال، يمكن تمرير الدوال والإجراءات كمعاملات إلى الدوال أو الإجراءات:

الإجراء ShowHex ( i : عدد صحيح ) ; ... نهاية ;الإجراء ShowInt ( i : عدد صحيح ) ; ... نهاية ;عرض الإجراء ( عرض الإجراء ( i : عدد صحيح )) ؛ فار ي : عدد صحيح ; يبدأ العرض ( ي ) النهاية ;... عرض توضيحي ( عرض القيم الست عشرية ) ؛ عرض توضيحي ( عرض القيم الصحيحة ) ؛ ...

المعالج المسبق

في بدايات لغة C، لم تكن هناك تعريفات للثوابت أو تعريفات للأنواع، وقد عُرّفت لغة C في الأصل بأنها تحتاج إلى " معالج مسبق "؛ وهو برنامج منفصل، يُمرّر، ويتولى تعريفات الثوابت والملفات المضمنة والماكرو ، وذلك لتقليل استهلاك الذاكرة. لاحقًا، مع معيار ANSI C، اكتسبت اللغة ميزات تعريفات الثوابت والأنواع، وأصبح المعالج المسبق جزءًا لا يتجزأ منها، مما أدى إلى الصيغة التي نراها اليوم.

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

أنواع الهروب

في لغة C، يمكن للمبرمج فحص تمثيل أي كائن على مستوى البايت عن طريق توجيه charمؤشر إليه:

int a ; char * p = ( char * )( &a a ); char c = * p ; // البايت الأول من a

قد يكون من الممكن القيام بشيء مماثل في لغة باسكال باستخدام سجل متغير غير مميز:

var a : عدد صحيح ; b : عدد حقيقي ; a2c : سجل case boolean of false : ( a : عدد صحيح ) ; true : ( b : عدد حقيقي ) ; end ; end ; begin a2c . b := b ; a := a2c . a ; end ;

على الرغم من إمكانية التحويل في معظم مترجمات ومفسرات لغة باسكال، إلا أنه حتى في الكود أعلاه، لا يُشترط أن تتشارك a2c.a و a2c.b نفس مساحة العناوين وفقًا لأي من معايير باسكال. وقد كتب نيكلاوس ويرث، مصمم لغة باسكال، عن إشكالية محاولة الهروب من النوع باستخدام هذا الأسلوب.

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

تستبعد العديد من اللغات الآن على وجه التحديد مثل هذه الهروب من الأنواع، على سبيل المثال Java و C# و Oberon الخاصة بـ Wirth .

الملفات

في لغة C، لا توجد الملفات كنوع بيانات مُدمج (يتم تعريفها في ملف رأس النظام)، وتتم جميع عمليات الإدخال والإخراج عبر استدعاءات المكتبات. أما لغة باسكال، فتتضمن معالجة الملفات مُدمجة فيها.

العبارات النموذجية المستخدمة لإجراء عمليات الإدخال والإخراج في كل لغة هي:

شركة:

printf ( "المجموع هو: %d \n " , x );

بلغة باسكال:

writeln ( 'المجموع هو: ' , x ) ;

يكمن الاختلاف الرئيسي في أن لغة C تستخدم "سلسلة تنسيق" تُفسَّر للعثور على وسائط دالة printf وتحويلها، بينما تُنفِّذ لغة باسكال ذلك تحت سيطرة معالج اللغة. يُمكن القول إن طريقة باسكال أسرع، لعدم وجود تفسير، لكن طريقة C قابلة للتوسيع بدرجة كبيرة.

تطبيقات وتوسعات لاحقة بلغة باسكال

أدمجت بعض تطبيقات باسكال الشائعة جميع بنيات لغة C تقريبًا في باسكال. ومن الأمثلة على ذلك تحويل الأنواع، [ 2 ] والقدرة على الحصول على عنوان أي متغير، سواء كان محليًا أو عامًا، وأنواع مختلفة من الأعداد الصحيحة ذات خصائص ترقية خاصة.

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

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

انظر أيضاً

ملحوظات

  1. كامب، بول-هينينغ (25 يوليو 2011)، "أغلى خطأ في بايت واحد"، مجلة ACM Queue ، 9 (7): 40-43 ، doi : 10.1145/2001562.2010365 ، ISSN 1542-7730 ، S2CID 30282393  
  2. "Typecast - Lazarus wiki" . wiki.freepascal.org . تم الاطلاع عليه بتاريخ 18-05-2024 .

للمزيد من القراءة