لماذا لم يتم تعديل المعلمة التي تم تمريرها حسب المرجع داخل الوظيفة؟

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

سؤال

لقد حصلت على دالة C في مكتبة ثابتة، دعنا نسميها A، بالواجهة التالية:

int A(unsigned int a, unsigned long long b, unsigned int *y, unsigned char *z);

ستغير هذه الوظيفة قيمة y an z (وهذا أمر مؤكد).أستخدمه من داخل مكتبة C++ ديناميكية، باستخدام "C" الخارجي.

والآن إليكم ما أذهلني:

  • تم ضبط y بشكل صحيح، ولم يتم تغيير z.ما أعنيه بالضبط هو أنه إذا تمت تهيئة كلاهما بقيمة (مشار إليها) تبلغ 666، فإن القيمة التي يشير إليها y ستتغير بعد المكالمة ولكن ليس القيمة التي يشير إليها z (لا تزال 666).
  • عند استدعاؤه من A C الثنائي ، تعمل هذه الوظيفة بسلاسة (يتم تعديل القيمة التي تم توجيهها بواسطة z).
  • إذا قمت بإنشاء مكتبة C وهمية مع وظيفة لها نفس النموذج الأولي، واستخدمتها من داخل مكتبة C++ الديناميكية الخاصة بي، فإنها تعمل بشكل جيد للغاية.إذا قمت بإعادة استخدام نفس المتغيرات للاتصال بـ A(..)، سأحصل على نفس النتيجة كما كان من قبل، ولم يتغير z.

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

من الواضح أنني عالق ولا أستطيع تغيير مكتبة C.هل لديك أي فكرة عما يمكن أن تكون المشكلة؟كنت أفكر في مشكلة في واجهة C/C++، على سبيل المثال الطريقة التي يتم بها تفسير char*.

يحرر :وأخيرا اكتشفت ما هي المشكلة.انظر أدناه إجابتي.

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

المحلول 9

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

إجابة مختصرة لمشكلتي:كانت المشكلة أن مكتبة C++ الخاصة بي تستخدم إصدارًا قديمًا من مكتبة C.غاب هذا الإصدار القديم عن الوسيطة الرابعة.ونتيجة لذلك، من الواضح أن الوسيطة الرابعة لم تتغير أبدًا.

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

C++ Lib (M) ---> dyn C++ lib (N) ---> C lib (P) v.1.0
     |
     ------> C lib (P) v.1.1

(N) هي مكتبة ديناميكية مرتبطة بشكل ثابت مع (P) الإصدار 1.0.قبل المترجم الاستدعاء من (M) إلى الدالة باستخدام 4 وسيطات لأنني قمت بالربط مع (P) الإصدار 1.1، ولكن في وقت التشغيل استخدم الإصدار القديم من (P).

لا تتردد في تعديل هذه الإجابة أو السؤال أو أن تطلب مني القيام بذلك.

نصائح أخرى

يبدو أن هناك اختلافًا بين الطريقة التي تتعامل بها مكتبة C ومترجم C++ يشتاق طويلا.أعتقد أن مكتبة C ربما تكون ما قبل معيار C89 وتتعامل فعليًا مع الإصدار 64 بت طويل طويل بطول 32 بت.تتعامل مكتبة C++ الخاصة بك معها بشكل صحيح وتضع 64 بت في مكدس الاستدعاءات وبالتالي تفسد y وz.ربما حاول استدعاء الوظيفة من خلال *int A(unsigned int a, unsigned long b, unsigned int *y, unsigned char ض), ، وشاهد ما ستحصل عليه.

مجرد فكرة.

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

أعتقد أنه يجب عليك يحرر رسالتك لتقديم المزيد من المعلومات من أجل الحصول على بعض الإجابات المعقولة.وعلى وجه الخصوص، لنبدأ بما يلي:-

  • ما هو النظام الأساسي لهذا الرمز:Windows ، Linux ، شيء مضمن أو ...؟
  • ما المترجم الذي تم تصميم المكتبة الثابتة C؟
  • ما المترجم الذي تم تصميم المكتبة الديناميكية C ++؟
  • ما هو المترجم الذي يمكن أن يتصل به المكتبة بنجاح؟
  • هل لديك مصحح على مستوى المصدر؟إذا كان الأمر كذلك ، هل يمكنك التقدم داخل رمز C من C ++.

ما لم تكن مخطئًا بشأن قيام A دائمًا بتعديل البيانات التي يشير إليها Z، فإن السبب الوحيد المحتمل لمشكلتك هو عدم التوافق بين اصطلاحات تمرير المعلمة.قد تكون مسألة "الطويل الطويل" إشارة إلى أن الأمور ليست كما تبدو.

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

بقدر ما أعرف، long long ليس جزءًا من معيار C++، ربما هذا هو مصدر مشكلتك.

لا أدري.حاول تصحيح الأخطاء في الخطوة A وشاهد ما يحدث (تنبيه رمز التجميع!)

ربما يمكنك تغليف الوظيفة الأصلية في مكتبة C التي تستدعيها من مكتبة C++ الخاصة بك؟

بناءً على النقطتين 2 و3، يبدو أن هذا يمكن أن ينجح.

إذا لم يكن الأمر كذلك، فإنه يوفر لك نقطة تصحيح أخرى للعثور على المزيد من الأدلة - تعرف على أي من مكتباتك التي يظهر الفشل فيها أولاً، وتحقق من سبب عمل 2 و3، ولكن هذا لا يعمل - ما هو الفرق الأدنى؟

يمكنك أيضًا محاولة فحص المكدس الذي تم إعداده بواسطة استدعاء وظيفتك في كل حالة للتحقق مما إذا كان الفرق موجودًا - مع الأخذ في الاعتبار اصطلاحات الاتصال المختلفة.

الخطوة 1:قارن المؤشرات y وz التي تم تمريرها من جانب C++ مع تلك التي تستقبلها الدالة C.

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

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

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

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

في برنامج C++ الخاص بك، تم الإعلان عن النموذج الأولي باستخدام extern "C"?

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