سؤال

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

إنه يعمل كمترجم مترجم خط على حدة ، مثل قذيفة ، إخراج الخط المترجم بعد إدخال خط. هذا يعني أن الملفات يمكن أن تكون cat/أنابيب لترجمة ملف كامل ، وكذلك حقيقة أنه يمكنك "الخروج من" shell "عن طريق الضغط على ^d ، والتي تم اكتشافها بواسطة stdin ضرب EOF.

كل شيء يعمل. ومع ذلك ، عندما أضغط ^d والخروج ، فإنه segfaults. ما زلت لا أستطيع فهم ما يسبب هذا.

تجميع مع -g -O0 يساعد قليلا أعلم الآن أن المشكلة تنشأ من مكالمة Strlen في Transpose عندما يتم الضغط على ^d. ومع ذلك ، يجب ألا يتم استدعاء Transpose خلال ^d ، لأن EOF صحيح!

Program received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:31
31    ../sysdeps/x86_64/multiarch/../strlen.S: No such file or directory.
    in ../sysdeps/x86_64/multiarch/../strlen.S
(gdb) where
#0  __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:31
#1  0x0000000000400b0e in transpose (s=0x0, capsDelta=120263, smallDelta=120257, numDelta=0) at mathtext.c:58
#2  0x0000000000400e2b in main (argc=2, argv=0x7fffffffe4b8) at mathtext.c:92
هل كانت مفيدة؟

المحلول

معظم استخدامات feof() هي خطأ - وهذا البرنامج يوضح ذلك تمامًا في هذه الحلقة الرئيسية:

char temp[1048576];
do {
    if (!strcmp(argv[1], "serifb"))
        transpose(fgets(temp, 1048576, stdin), 119808 - 'A', 119834 - 'a', 120782 - '0');
    else if (!strcmp(argv[1], "serifi"))
        transpose(fgets(temp, 1048576, stdin), 119860 - 'A', 119886 - 'a', 0);
    else if (!strcmp(argv[1], "serifbi"))
        transpose(fgets(temp, 1048576, stdin), 119912 - 'A', 119938 - 'a', 0);
    else if (!strcmp(argv[1], "sans"))
        transpose(fgets(temp, 1048576, stdin), 120224 - 'A', 120250 - 'a', 120802 - '0');
    else if (!strcmp(argv[1], "sansb"))
        transpose(fgets(temp, 1048576, stdin), 120276 - 'A', 120302 - 'a', 120812 - '0');
    else if (!strcmp(argv[1], "sansi"))
        transpose(fgets(temp, 1048576, stdin), 120328 - 'A', 120354 - 'a', 0);
    else if (!strcmp(argv[1], "sansbi"))
        transpose(fgets(temp, 1048576, stdin), 120380 - 'A', 120406 - 'a', 0);
    else if (!strcmp(argv[1], "mono"))
        transpose(fgets(temp, 1048576, stdin), 120432 - 'A', 120458 - 'a', 120822 - '0');
    else if (!strcmp(argv[1], "fullwidth"))
        transposeBlock(fgets(temp, 1048576, stdin), '!', '~', 65281 - '!');
    else return help();
} while(!feof(stdin));

في نهاية الملف ، fgets() سيعود NULL, ثم الاحتجاج التالي لـ feof() سوف يعود صحيح. لذا فإن النهج الصحيح هو اختبار قيمة الإرجاع لوظيفة الإدخال الخاصة بك - وبما أنك تقوم بهذا الاختبار على أي حال ، فلا داعي للاتصال feof() (ما لم تكن تريد التمييز بين خطأ في الملف عن نهاية الملف).

char temp[1048576];
while (fgets(temp, sizeof temp, stdin) != NULL) {
    if (!strcmp(argv[1], "serifb"))
        transpose(temp, 119808 - 'A', 119834 - 'a', 120782 - '0');
    else if (!strcmp(argv[1], "serifi"))
        transpose(temp, 119860 - 'A', 119886 - 'a', 0);
    else if (!strcmp(argv[1], "serifbi"))
        transpose(temp, 119912 - 'A', 119938 - 'a', 0);
    else if (!strcmp(argv[1], "sans"))
        transpose(temp, 120224 - 'A', 120250 - 'a', 120802 - '0');
    else if (!strcmp(argv[1], "sansb"))
        transpose(temp, 120276 - 'A', 120302 - 'a', 120812 - '0');
    else if (!strcmp(argv[1], "sansi"))
        transpose(temp, 120328 - 'A', 120354 - 'a', 0);
    else if (!strcmp(argv[1], "sansbi"))
        transpose(temp, 120380 - 'A', 120406 - 'a', 0);
    else if (!strcmp(argv[1], "mono"))
        transpose(temp, 120432 - 'A', 120458 - 'a', 120822 - '0');
    else if (!strcmp(argv[1], "fullwidth"))
        transposeBlock(temp, '!', '~', 65281 - '!');
    else return help();
}

نصائح أخرى

البرنامج الخاص بك هو dereferencing فارغ ، منذ ذلك الحين fgets إرجاع NULL على الخطأ أو EOF ، وأنت تمرير هذا مباشرة إلى التحول الذي يستخدم النتيجة بسذاجة.

feof لا يمكن التنبؤ بالمستقبل. لا يعلم أنها نهاية الملف حتى تضغط فعليًا على مفتاح ^d ، في الوقت الذي يعود فيه البرنامج في انتظار الإدخال في fgets. لن تنتج قراءة ملف الخطأ لأن جميع المدخلات موجودة بالفعل في البداية. تحقق من Null في وظيفة Transpose الخاصة بك.

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