[C] ما هي وظيفة "ثابتة"؟


Answers

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

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

يمكن وظائف العضو غير ثابت الوصول إلى جميع أعضاء البيانات من الطبقة: ثابت وغير ثابت. يمكن وظائف العضو الثابتة تعمل فقط على أعضاء البيانات الثابتة.

إحدى الطرق للتفكير في هذا أنه في أعضاء البيانات الثابتة C ++ ووظائف العضو الثابتة لا تنتمي إلى أي كائن ولكن إلى الفصل بأكمله.

Question

كان السؤال حول وظائف c العادية ، وليس الأساليب static c + ، كما هو موضح في التعليقات.

حسنا ، أنا أفهم ما هو متغير static ، ولكن ما هي وظيفة static ؟

ولماذا إذا أعلن عن وظيفة ، دعنا نقول void print_matrix ، دعونا نقول ac (بدون ah ) وتشمل "ac" - أحصل على "print_matrix@@....) already defined in a.obj" ، ولكن إذا أعلن أنها static void print_matrix ثم أنه يجمع؟

تحديث فقط لمجرد الامور - وأنا أعلم أن بما في ذلك .c سيئة ، كما أشار العديد منكم. أنا فقط أفعل ذلك لمسح الفضاء مؤقتا في main.c حتى لدي فكرة أفضل عن كيفية تجميع كل تلك الوظائف في ملفات .h و. .h المناسبة. مجرد حل مؤقت وسريع.




يعتمد الجواب على وظيفة ثابتة على اللغة:

1) في اللغات التي لا تحتوي على OOPS مثل C ، فهذا يعني أنه لا يمكن الوصول إلى الوظيفة إلا داخل الملف الذي تم تعريفه فيه.

2) في اللغات مع OOPS مثل C ++ ، فهذا يعني أنه يمكن استدعاء الدالة مباشرة على الفصل دون إنشاء مثيل له.




دالة ثابتة هي وظيفة يمكن استدعاؤها في الفصل نفسه ، على عكس مثيل الطبقة.

على سبيل المثال ، سيكون غير ثابت:

Person* tom = new Person();
tom->setName("Tom");

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

Person* tom = Person::createNewPerson();



أولاً: من المفيد بشكل عام تضمين ملف .cpp في ملف آخر - يؤدي إلى حدوث مشكلات مثل :-) الطريقة العادية هي إنشاء وحدات تصنيف منفصلة ، وإضافة ملف رأس للملف المضمن.

ثانيا:

لدى C ++ بعض المصطلحات المربكة هنا - لم أكن أعرف عنها حتى أشرنا في التعليقات.

أ) static functions - موروثة من C ، وما تتحدث عنه هنا. خارج أي صف. تعني الوظيفة الثابتة أنها غير مرئية خارج وحدة التجميع الحالية - لذلك في حالتك تحتوي a.obj على نسخة ولديك الشفرة الأخرى نسخة مستقلة. (نفث الملف التنفيذي النهائي مع نسخ متعددة من التعليمات البرمجية).

ب) static member function - ما هو "اتجاه كائن" يصف طريقة ثابتة. يعيش داخل الفصل. استدعاء هذا مع الفصل بدلاً من مثيل كائن.

هذان التعريفان الوظيفيان الثابتان مختلفان تمامًا. كن حذرا - هنا يكون التنين.




الحد الأدنى من المثال متعدد الملفات runnable

ac :

#include <stdio.h>

/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://.com/questions/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*void f() { puts("a f"); }*/

/* OK: only declared, not defined. Will use the one in main. */
void f(void);

/* OK: only visible to this file. */
static void sf() { puts("a sf"); }

void a() {
    f();
    sf();
}

main.c :

#include <stdio.h>

void a(void);        

void f() { puts("main f"); }

static void sf() { puts("main sf"); }

void m() {
    f();
    sf();
}

int main() {
    m();
    a();
    return 0;
}

تجميع :

gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o

الإخراج :

main f
main sf
main f
a sf

ترجمة

  • هناك نوعان من وظائف منفصلة sf ، واحد لكل ملف
  • هناك وظيفة واحدة مشتركة f

وكالعادة ، كلما كان النطاق أصغر ، كلما كان ذلك أفضل ، لذا قم دائماً بالإعلان عن الوظائف static إذا static .

في برمجة C ، غالباً ما يتم استخدام الملفات لتمثيل "classes" ، وتمثل الدوال static أساليب "خاصة" للفئة.

نمط C المشترك هو تمرير this الهيكل حوله كوسيطة "method" الأولى ، والتي هي أساسًا ما تعمل C ++ تحت غطاء المحرك.

ما تقول المعايير حول هذا الموضوع

C99 N1256 مسودة 6.7.1 "محددات فئة التخزين" تقول أن static هو "محدد فئة التخزين".

6.2.2 / 3 "ارتباطات المعرفات" تشير إلى أن static يعني ضمناً internal linkage :

إذا كان تعريف معرف نطاق ملف لكائن أو دالة يحتوي على محدد فئة التخزين من النوع الثابت ، فإن المعرّف له ارتباط داخلي.

و 6.2.2 / 2 يقول أن internal linkage يتصرف في مثالنا:

في مجموعة وحدات الترجمة والمكتبات التي تشكل برنامجًا كاملاً ، يشير كل تعريف لمعرف معين مع ارتباط خارجي إلى نفس الكائن أو الوظيفة. داخل وحدة ترجمة واحدة ، يشير كل تعريف لمعرف ذي ربط داخلي إلى نفس الكائن أو الوظيفة.

حيث "وحدة الترجمة" هي ملف مصدر بعد المعالجة المسبقة.

كيف تطبقها دول مجلس التعاون الخليجي لصالح ELF (Linux)؟

مع ملزمة STB_LOCAL .

إذا قمنا بتجميع:

int f() { return 0; }
static int sf() { return 0; }

وتفكيك جدول الرموز مع:

readelf -s main.o

الإخراج يحتوي على:

Num:    Value          Size Type    Bind   Vis      Ndx Name
  5: 000000000000000b    11 FUNC    LOCAL  DEFAULT    1 sf
  9: 0000000000000000    11 FUNC    GLOBAL DEFAULT    1 f

لذا فإن الربط هو الفرق الهام الوحيد بينهما. Value هي مجرد إزاحة في قسم .bss ، لذلك نتوقع أن تختلف.

يتم توثيق STB_LOCAL على مواصفات ELF على http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :

STB_LOCAL الرموز المحلية غير مرئية خارج ملف الكائن الذي يحتوي على تعريفها. قد توجد رموز محلية بنفس الاسم في عدة ملفات دون التداخل مع بعضها البعض

مما يجعلها الخيار الأمثل لتمثيل static .

وظائف دون ثابت هي STB_GLOBAL ، وتقول المواصفات:

عندما يجمع محرر الارتباطات عدة ملفات كائن قابل لإعادة النشر ، فإنه لا يسمح بتعريفات متعددة لرموز STB_GLOBAL بنفس الاسم.

وهو متماسك مع أخطاء الارتباط على عدة تعريفات غير ثابتة.

إذا قمنا بتحسين عملية التحسين باستخدام -O3 ، تتم إزالة رمز sf بالكامل من جدول الرموز: لا يمكن استخدامه من الخارج على أي حال. TODO لماذا تبقي على وظائف ثابتة على جدول الرموز على الإطلاق عندما لا يكون هناك تحسين؟ هل يمكن استخدامها لأي شيء؟

أنظر أيضا

جربها بنفسك

مثال على GitHub لتلعب معه.




Links