سؤال

لدي برنامج C ++ الذي تجميعه مع MINGW (دول مجلس التعاون الخليجي لنظام التشغيل Windows). باستخدام إصدار TDM من MingW الذي يتضمن دول مجلس التعاون الخليجي 4.4.1. الروابط القابلة للتنفيذ إلى ملفين مكتبة ثابتة (.A): إزعاجها هي مكتبة طرف ثالث مكتوبة في ج؛ الآخر هو مكتبة C ++، التي كتبها لي، والتي تستخدم مكتبة C توفر API الخاص بي C ++ الخاص بي.

يتم تنفيذ جزء (في رأيي، المفرط) من وظائف مكتبة C في وظائف مضمنة. لا يمكنك تجنب إدراج الوظائف المضمنة عند استخدام API Library في Library، ولكن عندما أحاول ربط كل شيء معا، أحصل على أخطاء ارتباط قائلا هناك تعريفا متعدد لجميع الوظائف المضمنة - كلاهما لدي دعا في مكتبة المجمع C ++ الخاصة بي، والتي لم أكن، أساسا أي شيء محدد مضبوطا في الرؤوس قد حصلت على وظيفة تم إنشاؤها به في كل من مكتبة C ومكتبة C ++.

لا تسبب أخطاء تعريف متعددة عند استخدام ملفات تضمين عدة مرات في ملفات .c أو .cpp مختلفة في نفس المشروع؛ المشكلة هي أنها تولد تعريفا واحدا لكل مكتبة.

كيف / لماذا هي المهام الرموز والرموز المترجم لهذه المهام المضمنة في كلتا المكتبتين؟ كيف يمكنني إجبارها على التوقف عن إنشاءها في التعليمات البرمجية الخاصة بي؟ هل هناك أداة يمكنني تشغيلها لتجريد الوظائف المكررة من ملف .a، أو طريقة لجعل الرابط يتجاهل تعريفات متعددة؟

(FYI، تتضمن مكتبة الطرف الثالثة #ifdef __cplusplus وحراس "ج" خارجيا في جميع رؤوسها؛ على أي حال إذا كانت هذه هي المشكلة، فلن يتسبب في تعريف متعدد للرمز، فإنه سيؤدي إلى وجود مشكلة عكسية لأن الرمز سوف أن تكون غير محددة أو مختلفة على الأقل.)

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

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

الجواب على هذا السؤال هو أن الملصق مضاعفة بالتأكيد المتغيرات, ، مشكلتي هي تعريف متعدد لوظائف مضمنة: كرر أخطاء تعريف متعددة من بما في ذلك نفس الرأس في CPPs متعددة

كان هذا برنامج MSVC، لكنني أستخدم MingW؛ أيضا، كانت مشكلة الملصق في هذا السؤال تعريف منشئ فئة C ++ خارج جسم الفصل في رأس، في حين أن مشكلتي مع وظائف C التي تتلاشى: ثابت ثابت مشكلة تعريف متعددة

تمت إعادة تسمية هذا الأحمق كل رمز C كملفات C ++ ولم يكن رمز C ++ - آمن: تعريف متعدد للكثير من STD :: وظائف عند الارتباط

كان هذا واحد فقط يريد معرفة سبب انتهاك قاعدة التعريف الواحدة لم يكن خطأ: سلوك لا يمكن التنبؤ بالوظائف المضمنة مع تعريفات مختلفة

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

المحلول

عليك أولا أن تفهم نموذج C99 المضمن - ربما هناك خطأ في رؤوسك. هناك نوعان من التعريفات للوظائف المضمنة مع الارتباط الخارجي (غير ثابت)

  • التعريف الخارجي
    يمكن أن يظهر هذا التعريف لوظيفة مرة واحدة فقط في البرنامج بأكمله، في TU مخصص. يوفر وظيفة تصدير يمكن استخدامها من TUS الأخرى.

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

كل تعريف لوظيفة له المتغيرات الثابتة المحلية الخاصة به, ، لأن تصريحاتهم المحلية ليس لها صلة (ليست مشتركة مثل في C ++). سيكون تعريف وظيفة غير ثابتة غير ثابتة هو تعريف مضمن إذا

  • كل إعلان وظيفة في TU يشمل المحرف inline, ، و
  • لا يوجد إعلان وظيفة في TU يشمل المحرف extern.

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

مثال يدل على استخدام خاطئ لل inline, ، لأنه يتضمن تعريفا خارجيا لوظيفة مرتين في اثنين من TUS، مما تسبب في خطأ تعريف متعدد

// included into two TUs
void f(void); // no inline specifier
inline void f(void) { }

البرنامج التالي خطير، لأن التحويل البرمجي مجاني لاستخدام التعريف الخارجي، ولكن البرنامج لا يوفر

// main.c, only TU of the program
inline void g(void) {
  printf("inline definition\n");
}

int main(void) {
  g(); // could use external definition!
}

لقد قمت ببعض حالات الاختبار باستخدام دول مجلس التعاون الخليجي مما يدل على الآلية أكثر:

ج الرئيسية

#include <stdio.h>

inline void f(void);

// inline definition of 'f'
inline void f(void) {
  printf("inline def main.c\n");
}

// defined in TU of second inline definition
void g(void);

// defined in TU of external definition
void h(void);

int main(void) {
  // unspecified whether external definition is used!
  f();
  g();
  h();

  // will probably use external definition. But since we won't compare
  // the address taken, the compiler can still use the inline definition.
  // To prevent it, i tried and succeeded using "volatile". 
  void (*volatile fp)() = &f;
  fp();
  return 0;
}

Main1.c.

#include <stdio.h>

inline void f(void);

// inline definition of 'f'
inline void f(void) {
  printf("inline def main1.c\n");
}

void g(void) {
  f();
}

Main2.c.

#include <stdio.h>

// external definition!
extern inline void f(void);

inline void f(void) {
  printf("external def\n");
}


void h(void) {
  f(); // calls external def
}

الآن، ينخرف البرنامج ما الذي توقعناه!

$ gcc -std=c99 -O2 main.c main1.c main2.c
inline def main.c
inline def main1.c
external def
external def

بالنظر إلى جدول الرموز، سوف نرى أن رمز تعريف مضمن لا يتم تصديره (من main1.o)، في حين يتم تصدير تعريف خارجي (من main2.o).


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

static inline void f(void) {
  printf("i'm unique in every TU\n");
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top