سؤال

العديد من المبرمجين الشباب هل تعلمت فائدة إدراج العديد من الطباعة إلى وحدة تحكم البيانات "here1," "here2" و ذلك في نقاط مختلفة في رمز إلى معرفة عندما البرامج تسير بشكل منحرف.هذه القوة الغاشمة التصحيح التقنية وفرت لي مرات عديدة في جميع أنحاء بلدي CS الدراسات.ومع ذلك ، عندما بدأت البرمجة في C, أنا تعثرت على مشكلة مثيرة للاهتمام.إذا كنت تحاول تشغيل

void* test;

printf("hello world");
test[5] = 234;

بالطبع أنا على segfault لا malloc التعرف على الذاكرة testChar.ومع ذلك, كنت أعتقد منطقيا أن "مرحبا العالم" سيكون المطبوعة قبل seg خطأ يحدث ، لأن ذلك هو تدفق رمز ، ولكن في تجربتي, هو دائما حال seg خطأ يحدث أولا ، و "مرحبا العالم" أبدا المطبوعة إلى وحدة التحكم في كل شيء.(لم أكن قادرة على اختبار هذا بالضبط سبيل المثال ، لكنني واجهت هذا النوع من الوضع عدة مرات باستخدام دول مجلس التعاون الخليجي على لينكس مربع.) أعتقد أن هذا له علاقة مع أي مترجم إعادة ترتيب بعض الأشياء و/أو printf باستخدام نوع من المخزن المؤقت مسح بشكل غير متزامن ، وبالتالي عدم الفورية.هذا هو تماما تكهنات من جانبي لأنني بصراحة لا أعرف لماذا يحدث ذلك.في أي لغة أخرى التي استخدمت ، بغض النظر عن مشكلة "testChar =..." خط تسبب, "مرحبا العالم" ستظل مطبوعة ، وبالتالي أستطيع تحديد أين تكمن المشكلة.

سؤالي هو لماذا يحدث هذا عندما أنا البرمجة C ؟ لماذا لم مرحبا العالم المطبوعة أولا ؟ وثانيا هل هناك أفضل البرمجة C التصحيح تقنية من هذا أن يحقق نفس الشيء ؟ كما في وسيلة سهلة/طريقة بديهية أن تجد السطر من التعليمات البرمجية هو مشكلة ؟

تحرير:أعطى العامل سبيل المثال عن طريق الصدفة هاها.ما لدي الآن يجب أن يسبب segfault.انه مضحك كيف عادة عندما لا تريد segfault يمكنني الحصول على واحد الآن عندما كنت في الواقع أريد واحدة كتبت مدونة قانونية!

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

المحلول

يعد الرمز الذي نشرته قانونيا تماما ويجب عدم تناول Segfault - ليست هناك حاجة إلى أي شيء. يجب أن تكمن مشكلتك في مكان آخر - يرجى نشر أصغر مثال على التعليمات البرمجية التي تسبب المشكلة.

تعديل: لقد قمت الآن بتحرير التعليمات البرمجية للحصول على معنى مختلف تماما. ومع ذلك، فإن السبب في عدم عرض "Hello World" هو أن المخزن المؤقت الإخراج لم يتم مسحه. حاول addinig.

fflush( stdout );

بعد الطباعة.

فيما يتعلق بمكان تحديد مصدر المشكلة لديك بضع خيارات:

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

نصائح أخرى

printf يكتب إلى Stdout، الذي يتم تخزيعه. في بعض الأحيان لا يتم مسح المخزن المؤقت قبل تعطل البرنامج الخاص بك حتى لا ترى الناتج أبدا. طريقتان لتجنب هذا:

  1. استعمال fprintf( stderr, "error string" ); منذ stderr ليست مخزنة.
  2. أضف مكالمة fflush( stdout ); بعد مكالمة الطباعة.

كما قال نيل والآخرون، الكود كما هو مكتوب جيد. هذا هو، حتى تبدأ تعديل المخزن المؤقت ذلك testChar نقاط ل.

"كما هو الحال في، طريقة سهلة / بديهية للعثور على خط التعليمات البرمجية التي هي مشكلة؟"

استخدم GDB (أو أي مصحح أخطاء آخر).

للعثور على حيث يخطئ البرنامج الخاص بك. -g الخيار (لتضمين رموز التصحيح الأخطاء) قم بتشغيل التطبيق الخاص بك من GDB, ، سوف تتوقف على خطأ SEG.

يمكنك بعد ذلك النظر في BackTrace مع bt أمر أن نرى عند أي نقطة حصلت على خطأ SEG.

مثال:

> gdb ./x
(gdb) r
Starting program: /proj/cpp/arr/x 
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x000019a9 in willfail () at main.cpp:22
22          *a = 3;
(gdb) bt
#0  0x000019a9 in willfail () at main.cpp:22
#1  0x00001e32 in main () at main.cpp:49
(gdb) 

يتم تخزين الإخراج بشكل افتراضي، يحدث Segfault قبل كتابة الإخراج بالفعل إلى Stdout. محاولة:

fprintf(stderr, "hello, world\n");

(stderr غير معروف بشكل افتراضي.)

هذا الرمز يجب أن لا segfault. أنت مجرد تعيين مؤشر إلى سلسلة حرفية إلى متغير مؤشر. ستكون الأمور مختلفة إذا كنت على سبيل المثال strcpy لنسخ الاشياء مع مؤشر غير صالح.

قد تكون الرسالة التي لا تظهر بسبب I / O مخزن مؤقتا. طباعة حرف جديد \n أو أتصل fflush لمسة المخزن المؤقت الإخراج.

لديك اثنين من المشاكل.الأول هو أن (الأصلي) رمز لن segfault.انها صالحة تماما أن تعيين هذه السلسلة مستمرة إلى شار المؤشر.ولكن لنترك هذا جانبا الآن والتظاهر كنت قد وضعت شيئا ما هناك أن segfault.

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

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

printf ("DEBUG point 72\n"); fflush (stdout); fsync (fileno (stdout));

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

void* test;

printf("hello world");
test[5] = 234;

من المحتمل أن يتم تخزين "Hello World" من قبل النظام في مكان ما ولا يتم طباعته على الفور إلى الشاشة. في انتظار المخزنة للحصول على فرصة لأي عملية / موضوع / أي شيء مسؤول عن كتابة الشاشة يمكن أن يكون لديه فرصة لمعالجة ذلك. وبينما انتظارها (وربما تخزين البيانات الأخرى للإخراج) أنت وظيفة تشطيب. يأتي على الوصول غير المشروع و Segfafts.

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