سؤال

منذ عصر الديناصورات، لدى Turbo Pascal ودلفي في الوقت الحاضر إجراءات Write() وWriteLn() التي تقوم ببعض الأشياء الرائعة بهدوء.

  • عدد المعلمات متغير.

  • يمكن أن يكون كل متغير من جميع الأنواع؛يمكنك توفير الأعداد الصحيحة، والزوجية، والسلاسل، والقيم المنطقية، وخلطها جميعًا بأي ترتيب؛

  • يمكنك توفير معلمات إضافية لكل وسيطة:

Write('Hello':10,'World!':7);// معلمات المحاذاة

  • حتى أنه يظهر بطريقة خاصة في قائمة إكمال التعليمات البرمجية:
    • اكتب ([فار F:ملف]؛ص1؛[...،بن])
    • WriteLn ([var F:File];[ ص1؛[...,PN]] )

الآن بعد أن كنت أكتب هذا، لاحظت أن Write وWriteLn ليس لهما نفس الأقواس في القائمة المنسدلة لإكمال التعليمات البرمجية.لذلك يبدو أن هذا لم يتم إنشاؤه تلقائيًا، ولكن تم ترميزه بواسطة شخص ما.

على أية حال، هل أنا قادر على كتابة إجراءات مثل هذه بنفسي، أم أن كل هذا عبارة عن خدعة سحرية للمترجم؟

هل كانت مفيدة؟

المحلول

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

باختصار، لا توجد طريقة لتنفيذ نسختك الخاصة التي تقوم بنفس المهام التي يقوم بها برنامج writeln المدمج دون تعديل المترجم.

نصائح أخرى

كما قال Allen، لا يمكنك كتابة وظيفتك الخاصة التي تقوم بنفس الأشياء.

ومع ذلك، يمكنك كتابة برنامج تشغيل ملف نصي يقوم بشيء مخصص وعند استخدام Write(ln) القياسي للكتابة إلى برنامج تشغيل الملف النصي الخاص بك.لقد فعلنا ذلك في أيام DOS القديمة :)

("برنامج التشغيل" في سياق العبارة السابقة هو مجرد جزء من كود باسكال الذي تم ربطه بالنظام عن طريق تبديل المؤشر في وحدة النظام IIRC.لقد مر وقت طويل منذ آخر مرة استخدمت فيها هذه الخدعة.)

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

بعد قولي هذا، IIRC، GNU Pascal دعنا نقول شيئًا مثل:الإجراء فو (أ:عدد صحيح؛ب:عدد صحيح؛...)؛

حاول البحث في مستندات لغة المترجم الخاص بك عن "قوائم الوسائط المتغيرة" أو "المصفوفات المتوافقة".فيما يلي مثال على ما يلي: http://www.gnu-pascal.de/demos/conformantdemo.pas.

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

ومع ذلك، إلا إذا كنت تكتب الدالة "writeln" (التي تمت كتابتها بالفعل)، فمن المحتمل ألا تفعل ذلك يحتاج لتنفيذ إجراء باستخدام وسائط متغيرة.حاول التكرار أو العودية بدلا من ذلك :)

إنه سلوك مترجم سحري وليس إجراءً عاديًا.ولا، لا توجد طريقة لكتابة مثل هذه الإجراءات الفرعية (للأسف!).يحل إنشاء التعليمات البرمجية عدد المعلمات الفعلية وأنواعها ويترجم إلى مكالمات RTL المناسبة (على سبيل المثال. شارع ()) في وقت التجميع.وهذا يعارض المقترح في كثير من الأحيان مجموعة من الثابت (معلمة رسمية لصفيف متغير واحد، في الواقع) مما يؤدي إلى القيام بنفس الشيء في وقت التشغيل.أجد لاحقًا نهجًا أخرقًا، فهو يضعف إمكانية قراءة التعليمات البرمجية إلى حد ما، وقام Bugland (Borland/Inprise/Codegear/Embarcadero/اسمه) بكسر Code Insight لمنشئي المصفوفات المفتوحة المتنوعة (نعم، أنا أهتم، أستخدم OutputDebugString(PChar(Format ('...'، [...])))) ولا يعمل إكمال التعليمات البرمجية بشكل صحيح (أو على الإطلاق) هناك.لذا، فإن أقرب طريقة ممكنة لمحاكاة السلوك السحري هي الإعلان عن الكثير من الإجراءات الفرعية المثقلة (في الواقع الكثير منها، واحد لكل نوع معلمة رسمي محدد في الموضع المحدد).يمكن للمرء أن يطلق على هذا اسم "الخدعة" أيضًا، ولكن هذه هي الطريقة الوحيدة للحصول على مرونة قائمة المعلمات المتغيرة ويمكن إخفاؤها في وحدة منفصلة.

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

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

procedure MyProc(args : array of const);

(لقد مرت بضع سنوات وليس لدي أدلة، لذا تحقق من التفاصيل قبل المتابعة).يمنحك هذا مجموعة مفتوحة من TVarData (أو شيء من هذا القبيل) يمكنك استخراج RTTI منه.

ملاحظة واحدة بالرغم من ذلك:لا أعتقد أنك ستكون قادرًا على مطابقة صيغة التنسيق x:y (وهو أمر خاص)، ومن المحتمل أن تضطر إلى استخدام غلاف أكثر تفصيلاً قليلاً.

لقد قيل معظمها بالفعل، لكني أحب أن أضيف بعض الأشياء.

أولاً يمكنك استخدام وظيفة التنسيق.إنه لأمر رائع تحويل أي نوع من المتغيرات تقريبًا إلى سلسلة والتحكم في حجمها.على الرغم من أن له عيوبه:

myvar := 1;
while myvar<10000 do begin
  Memo.Lines.Add(Format('(%3d)', [myVar]));
  myvar := myvar * 10;
end;

ينتج عنه:

(  1)
( 10)
(100)
(1000)

لذا فإن الحجم هو الحجم الأدنى (تمامًا مثل البناء :x:y).

للحصول على الحد الأدنى من الوسائط المتغيرة، يمكنك العمل باستخدام المعلمات الافتراضية والوظائف المحملة بشكل زائد:

procedure WriteSome(const A1: string; const A2: string = ''; const A3: string = '');

أو

procedure WriteSome(const A1: string); overload;
procedure WriteSome(const A1: Integer); overload;

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

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

ملاحظة.

ولكن كما أشار MarkusQ، يمكن لبعض متغيرات Pascal (Free Pascal، وKylix، وما إلى ذلك) تسهيل الوسائط المتغيرة.آخر مرة قمت فيها بالعبث بـ Pascal، منذ أيام DOS، Turbo Pascal 7.

لا يعتمد Writeln على "صفيف const"، ولكنه متحلل بواسطة المترجم إلى استدعاءات مختلفة تحول الوسائط إلى سلسلة ثم تستدعي سلسلة الكتابة البدائية."LN" هي مجرد وظيفة تكتب نهاية السطر كسلسلة.(يعتمد على نظام التشغيل).تعد متغيرات الإجراء (مؤشرات الوظائف) للأوليات جزءًا من نوع الملف (Textrec/filerec)، ولهذا السبب يمكن تخصيصها.(على سبيل المثالتعيينCrt في TP)

إذا كان الوضع {$I+} قيد التشغيل، فسيتم استدعاء وظيفة iocheck بعد كل عنصر.

إن بنية GPC المذكورة أعلاه هي عبارة عن مصفوفة C المفتوحة غير المحدودة.تدعم FPC (و afaik Delphi أيضًا) هذا أيضًا، ولكن بصيغة مختلفة.

إجراء ما (a:صفيف const);cdecl;

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

على الرغم من أن هذا ليس إجابة مباشرة على سؤالك، إلا أنني أود إضافة التعليق التالي:لقد قمت مؤخرًا بإعادة كتابة بعض التعليمات البرمجية باستخدام بناء جملة Writeln(...) لاستخدام StringList، وملء "السطور" بـ Format(...) ووظائف IntToStr(...) وFloatToStr(...) ووظائف IntToStr(...) يحب.

وكان السبب الرئيسي لهذا التغيير هو تحسين السرعة.يعد استخدام StringList وSaveFileTo أسرع بكثير من الجمع بين WriteLn وWrite.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top