سؤال

اعتقدت منذ فترة طويلة أنه في لغة C، يجب الإعلان عن جميع المتغيرات في بداية الوظيفة.أعلم أن القواعد في C99 هي نفسها الموجودة في C++، ولكن ما هي قواعد وضع الإعلان المتغير لـ C89/ANSI C؟

يتم تجميع التعليمة البرمجية التالية بنجاح مع gcc -std=c89 و gcc -ansi:

#include <stdio.h>
int main() {
    int i;
    for (i = 0; i < 10; i++) {
        char c = (i % 95) + 32;
        printf("%i: %c\n", i, c);
        char *s;
        s = "some string";
        puts(s);
    }
    return 0;
}

ألا ينبغي لتصريحات c و s هل يسبب خطأ في وضع C89/ANSI؟

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

المحلول

ويجمع بنجاح لدول مجلس التعاون الخليجي تسمح له باعتباره امتدادا GNU، على الرغم من انها ليست جزءا من معيار C89 أو ANSI. إذا كنت ترغب في الالتزام الصارم لتلك المعايير، يجب أن تجتاز العلم -pedantic.

نصائح أخرى

لC89، يجب أن تقوم بتعريف كل من المتغيرات الخاصة بك في بداية <م> كتلة نطاق .

وهكذا، إعلان char c صالحا كما هو الحال في الجزء العلوي من لكتلة نطاق حلقة. ولكن، يجب أن يكون إعلان char *s خطأ.

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

لسوء الحظ، يستمر C++ في قبول طريقة الإعلان القديمة والأعلى للتوافق مع الإصدارات السابقة مع C (سحب توافق C واحد من العديد من الآخرين ...) لكن C++ يحاول الابتعاد عنه:

  • لا يسمح تصميم مراجع C++ حتى بمثل هذا التجمع العلوي للكتلة.
  • إذا قمت بفصل الإعلان وتهيئة لغة C++ المحلية هدف ثم تدفع تكلفة المُنشئ الإضافي مجانًا.إذا لم يكن مُنشئ no-arg موجودًا، فلا يُسمح لك بالفصل بين الاثنين!

يبدأ C99 في تحريك C في نفس الاتجاه.

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

https://www.securecoding.cert.org/confluence/display/cplusplus/DCL19-CPP.+Initialize+automatic+local+variables+on+declaration

من وجهة نظر قابلية الصيانة، وليس من وجهة نظر نحوية، هناك على الأقل ثلاثة مسارات فكرية:

  1. قم بتعريف جميع المتغيرات في بداية الوظيفة بحيث تكون في مكان واحد وستتمكن من رؤية القائمة الشاملة في لمحة سريعة.

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

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

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

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

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

وC89 يتطلب أن يعلن المتغيرات قبل أية عبارات أخرى داخل كل نطاق، تسمح المعايير لاحقة إعلان أقرب إلى استخدام (والتي يمكن أن تكون أكثر سهولة وأكثر كفاءة)، وخصوصا إعلان متزامن وتهيئة متغير التحكم في حلقة "ل 'الحلقات.

وكما لوحظ أن هناك مدرستين في التفكير في هذا الشأن.

1) إعلان كل شيء في الجزء العلوي من الوظائف لهذا العام هو 1987.

2) إعلان الأقرب إلى أول استخدام وفي أصغر نطاق ممكن.

وجوابي على ذلك هو القيام على حد سواء! اسمحوا لي أن أشرح:

لوظائف طويلة، 1) يجعل من الصعب جدا إعادة بيع ديون. إذا كنت تعمل في مصدر برنامج حيث المطورين هي ضد فكرة الوظائف الفرعية، ثم سيكون لديك 50 تعريفات المتغير في بداية وظيفة وبعضها قد يكون مجرد "أنا" لحلقة مقابل هذا في غاية الجزء السفلي من وظيفة.

وبالتالي أنا وضعت إعلانا-في-ث-أعلى PTSD من هذا وحاولت أن تفعل الخيار 2) دينيا.

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

وكما أن نموذج مضاد من "إعلان وتعيين إلى NULL" عندما كنت تريد أن تعلن في الأعلى ولكن لم تقم بإجراء بعض العمليات الحسابية اللازمة للتهيئة يتم حل لأن الأشياء التي تحتاج من المرجح أن تكون وردت لتهيئة الحجج.

وحتى الآن تفكيري هو أنه يجب أن تعلن في الجزء العلوي من وظائف وأقرب ما يمكن إلى أول استخدام. لذلك على حد سواء! وسيلة لتحقيق ذلك هي مع الوظائف الفرعية تنقسم أيضا.

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

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

int foo = 0;
<code that uses foo>

int bar = 1;
<code that uses bar>

<code that uses foo>

والآن، وتحديد كتلة نطاق الذي يبدأ قبل إعلان ونقل نهاية حتى يجمع البرنامج

{
    int foo = 0;
    <code that uses foo>
}

int bar = 1;
<code that uses bar>

>>> First compilation error here
<code that uses foo>

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

{
    int foo = 0;
    <code that uses foo>
}

<code that uses foo>

int bar = 1;
<code that uses bar>

إذا يمكن أن تحول النظام، وهذا ربما ما تريد لأنه يقصر من عمر القيم المؤقتة.

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

int i;

for(i = 0; i < 8; ++i){
    ...
}

<some stuff>

for(i = 3; i < 32; ++i){
    ...
}

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

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

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

سأقتبس بعض العبارات من دليل الإصدار 4.7.0 من دليل دول مجلس التعاون الخليجي للحصول على شرح واضح.

"يمكن للمترجم قبول العديد من المعايير الأساسية، مثل "c90" أو "c++98"، ولهجات GNU لتلك المعايير، مثل "gnu90" أو "gnu++98".من خلال تحديد معيار أساسي، سيقبل المترجم جميع البرامج التي تتبع هذا المعيار وتلك التي تستخدم امتدادات GNU التي لا تتعارض معه.على سبيل المثال، يقوم '-std=c90' بإيقاف تشغيل ميزات معينة من دول مجلس التعاون الخليجي غير المتوافقة مع ISO C90، مثل الكلمات الأساسية asm وtypeof، ولكن ليس امتدادات GNU الأخرى التي ليس لها معنى في ISO C90، مثل حذف الوسط مصطلح ؟:تعبير."

أعتقد أن النقطة الأساسية في سؤالك هي لماذا لا يتوافق مجلس التعاون الخليجي مع C89 حتى لو تم استخدام الخيار "-std=c89".لا أعرف إصدار دول مجلس التعاون الخليجي الخاص بك، ولكن أعتقد أنه لن يكون هناك فرق كبير.أخبرنا مطور gcc أن الخيار "-std=c89" يعني فقط إيقاف تشغيل الامتدادات التي تتعارض مع C89.لذلك، لا علاقة للأمر ببعض الامتدادات التي ليس لها معنى في C89.والامتداد الذي لا يقيد موضع إعلان المتغير ينتمي إلى الامتدادات التي لا تتعارض مع C89.

لكي نكون صادقين، سيعتقد الجميع أنه يجب أن يتوافق مع C89 تمامًا عند النظرة الأولى للخيار "-std=c89".لكنها لا تفعل ذلك.أما بالنسبة لمشكلة إعلان جميع المتغيرات في البداية أفضل أو أسوأ فهي مجرد مسألة عادة.

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