تعريفات المتغير في رأس الملفات - ثابت أو لا ؟

StackOverflow https://stackoverflow.com/questions/92546

  •  01-07-2019
  •  | 
  •  

سؤال

عند إعادة بيع ديون بعيدا بعض #defines جئت عبر إعلانات مشابهة لما يلي في C++ رأس الملف:

static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;

السؤال هو ما الفرق ، إن وجد ، سيكون ثابت ؟ علما بأن متعددة إدراج رؤوس لا يكون ذلك ممكنا بسبب الكلاسيكية #ifndef HEADER #define HEADER #endif خدعة (إذا كان ذلك من المسائل).

لا ثابت يعني نسخة واحدة فقط من VAL يتم إنشاؤه في حالة رأس يتم تضمينها من قبل أكثر من مصدر الملف ؟

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

المحلول

على static يعني أنه سيكون هناك نسخة واحدة من VAL خلق لكل ملف مصدر يتم تضمينه في.ولكن هذا يعني أيضا أن عدة شوائب لن تؤدي في عدة تعاريف VAL من شأنها أن تصطدم في وقت الارتباط.في C ، دون static سوف تحتاج إلى التأكد من أن مصدر واحد فقط ملف تعريف VAL في حين أن غيرها من الملفات المصدر أعلنت extern.عادة ما تكون واحدة أن تفعل ذلك من خلال تحديد ذلك (ربما مع مهيئ) في المصدر الملف ووضع extern الإعلان في رأس الملف.

static المتغيرات على المستوى العالمي مرئية فقط في بلدهم الملف المصدر ما إذا كانت هناك طريق أو في الملف الرئيسي.


ملاحظة المحرر: في C++ ، const الأجسام لا static ولا extern كلمات في الإعلان ضمنا static.

نصائح أخرى

على static و extern العلامات في الملف-راقب المتغيرات تحديد ما إذا كان يمكن الوصول إليها في الترجمة الأخرى الوحدات (أيأخرى .c أو .cpp الملفات).

  • static يعطي متغير الداخلية الربط ، إخفائه عن غيرها من وحدات الترجمة.غير أن المتغيرات الداخلية الربط يمكن تعريفها في الترجمة متعددة الوحدات.

  • extern يعطي متغير خارجي الربط ، مما يجعلها مرئية أخرى وحدات الترجمة.عادة هذا يعني أن المتغير يجب أن تكون محددة في وحدة الترجمة.

الافتراضي (عندما لا تحديد static أو extern) هي واحدة من تلك المناطق في C و C++ تختلف.

  • في C ، ملفات-راقب المتغيرات extern (الخارجية الربط) بشكل افتراضي.إذا كنت تستخدم C ، VAL هو static و ANOTHER_VAL هو extern.

  • في C++ ، ملفات-راقب المتغيرات static (الداخلية الروابط) بشكل افتراضي إذا كانت const, ، extern بشكل افتراضي إذا لم يتم.إذا كنت تستخدم C++, كل VAL و ANOTHER_VAL هي static.

من مشروع ج المواصفات:

6.2.2 الروابط من المعرفات ...-5 - إذا كان إعلان معرف الوظيفة لا تخزين من الدرجة محدد ، الربط يتم تحديد بالضبط كما لو كانت معلنة مع فئة تخزين محدد خارجي.إذا إعلان معرف كائن لديه ملف نطاق أي فئة تخزين محدد, وصلتها خارجي.

من مشروع C++ مواصفات:

7.1.1 - فئة تخزين محددات [dcl.stc] ...-6 - اسم أعلن في مساحة اسم النطاق دون تخزين الدرجة محدد لديه الخارجية الربط ما لم يكن قد الداخلي الربط بسبب إعلان سابق شريطة أن لا أعلن const.أعلن الكائنات const وليس أعلن صراحة extern الداخلية الربط.

ثابت يعني يمكنك الحصول على نسخة واحدة لكل ملف ، ولكن على عكس البعض الآخر قال إنه قانوني تماما للقيام بذلك.يمكنك بسهولة اختبار هذا مع رمز صغير العينة:

الاختبار.h:

static int TEST = 0;
void test();

test1.cpp:

#include <iostream>
#include "test.h"

int main(void) {
    std::cout << &TEST << std::endl;
    test();
}

test2.cpp:

#include <iostream>
#include "test.h"

void test() {
    std::cout << &TEST << std::endl;
}

تشغيل هذا يمنحك هذا الناتج:

0x446020
0x446040

const المتغيرات في C++ الداخلية الربط.وذلك باستخدام static ليس له أي تأثير.

أ.ح

const int i = 10;

one.cpp

#include "a.h"

func()
{
   cout << i;
}

two.cpp

#include "a.h"

func1()
{
   cout << i;
}

إذا كان هذا برنامج C, سوف تحصل على 'متعددة تعريف' خطأ i (الخارجية بسبب الربط).

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

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

في هذه الحالة بالذات ، 'ثابت' الكلمة لا يبدو أن تقديم أي فائدة.قد يكون في عداد المفقودين شيء ، ولكن يبدو أنه لا يهم .. أنا لم أر قط أي شيء مثل هذا من قبل.

أما بالنسبة inlining في هذه الحالة المتغير المرجح المضمنة ، ولكن هذا فقط لأنه أعلن const.مترجم قد تكون أكثر عرضة مضمنة وحدة متغيرات ثابتة ، ولكن هذا يعتمد على الحالة البرمجية التي يتم تجميعها.ليس هناك ما يضمن أن المترجم مضمنة 'توازن'.

ج كتاب (مجانية على الانترنت) قد فصل عن الربط ، وهو ما يفسر معنى "ثابت" في مزيد من التفاصيل (على الرغم من أن الجواب الصحيح هو بالفعل في التعليقات):http://publications.gbdirect.co.uk/c_book/chapter4/linkage.html

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

لا.فال تكون دائما محددة بشكل منفصل في كل ملف يتضمن رأس.

معايير C و C++ هل يؤدي اختلاف في هذه الحالة.

في C ، ملفات-راقب المتغيرات extern بشكل افتراضي.إذا كنت تستخدم C ، فال هو ثابت و ANOTHER_VAL هو خارجي.

علما بأن الحديث linkers قد يشكو ANOTHER_VAL إذا كان رأس يتم تضمينها في ملفات مختلفة (نفس اسم المعرف مرتين), و بالتأكيد يشكو إذا ANOTHER_VAL كان initialised إلى قيمة مختلفة في ملف آخر

في C++ ، ملفات-راقب المتغيرات ثابتة بشكل افتراضي إذا كانت const ، extern بشكل افتراضي إذا لم يتم.إذا كنت تستخدم C++ ، سواء فال و ANOTHER_VAL هي ثابتة.

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

  • تصحيح الخيارات
  • عنوان المتخذة في ملف
  • مترجم يخصص دائما التخزين (مجمع const أنواع لا يمكن بسهولة أن المضمنة ، حتى يصبح حالة خاصة بالنسبة أنواع أساسية)

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

على افتراض أن هذه الإعلانات على النطاق العالمي (أيلا الأعضاء المتغيرات) ، ثم:

ثابت يعني داخلي 'الربط'.في هذه الحالة, لأنه أعلن const هذا يمكن أن يكون الأمثل/inlined من قبل المترجم.إذا قمت بحذف const ثم المترجم يجب تخصيص التخزين في تجميع كل وحدة.

من خلال حذف ثابت الربط هو extern بشكل افتراضي.مرة أخرى, كنت قد تم حفظها من قبل constنيس - المترجم يمكن تحسين/مضمنة الاستخدام.إذا قمت بإسقاط const ثم سوف تحصل على ضرب الرموز المعرفة خطأ في وقت الارتباط.

const المتغيرات بشكل افتراضي ثابت في C++, ولكن extern C.حتى إذا كنت تستخدم C++ هذا لا معنى له ما البناء للاستخدام.

(7.11.6 C++ 2003 ، Apexndix C عينات)

على سبيل المثال في مقارنة ترجمة/رابط مصادر C و C++ برنامج:

bruziuz:~/test$ cat a.c
const int b = 22;
int main(){return 0;}
bruziuz:~/test$ cat b.c
const int b=2;
bruziuz:~/test$ gcc -x c -std=c89 a.c b.c
/tmp/ccSKKIRZ.o:(.rodata+0x0): multiple definition of `b'
/tmp/ccDSd0V3.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
bruziuz:~/test$ gcc -x c++ -std=c++03 a.c b.c 
bruziuz:~/test$ 
bruziuz:~/test$ gcc --version | head -n1
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609

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

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

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

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