2.7 טיפול בשגיאות

מבנה נתונים ואלגוריתמים

 

 

תוכנית או חלק של תוכנית אינם נחשבים כגמורים ומושלמים אם לא מבוצע השלב של טיפול הולם בשגיאות. תקלה בלתי צפויה בתוכנית הינה הרת אסון. במקרה הטוב הדבר גורם לתסכול של המשתמש בתוכנית, שעשוי לבזבז דקות או שעות של עבודה, אך במערכות תומכות חיים, אפילו השגיאה הטריוויאלית ביותר בתוכנית, במידה שגורמת להמשך לא תקין של התוכנית, עלולה לגרום להרג אדם.

 

אם השגיאה היא פטאלית, במובן שהתוכנית אינה יכולה להמשיך כראוי, אזי התוכנית אמורה לאפשר "מוות נשיקה":

·        לידע את השתמש מדוע היא מתה.

·        לשמור מידע רב ככל האפשר ממצב התוכנית.

 

 

2.7.1 הגדרת שגיאות

 

הצעד הראשון בהבנת אופן הטיפול בשגיאות, הוא להגדיר במדויק מה נחשב כשגיאה. הגדרה זהירה של כל מרכיב תוכנה הוא חלק מתהליך זה. התנאים המקדימים של מתודות ה- ADT, יגדירו את מצבי המערכת (מצבי הקלט) אשר ניתנים לעיבוד. התנאים המאוחרים של כל מתודה אמורים להגדיר בברור את תוצאת העיבוד של כל מצב קלט מתאים. לכן, אם נביט במתודה הבאה:

 

        int f( some_class a, int i )
        /* PRE-CONDITION: i >= 0 */
        /* POST-CONDITION:
        if ( i == 0 )
           return 0 and a is unaltered
        else
           return 1 and update a's i-th element by ... */ 

 

·        הגדרה זו אומרת כי שהקלט 0==i  הוא חסר משמעות, וכי המתודה  f אמורה לציין זאת בכך שתחזיר 0, אחרת עליה להתעלם.

·        מהמתודה f מצופה לטפל בצורה תקינה בכל ערך חיובי של i.

·        התנהגות המתודה f אינה מוגדרת עבור ערכים שלילים של i.

·        התוכנית תציין כי זו טעות לקרוא ל- f עם ערך שלילי של i.

 

לכן, הגדרה מלאה תציין:

 

·        את כל המצבים המתאימים של הקלט.

·        את פעולתה של המתודה לכל מצב קלט מתאים.

 

על ידי הגדרה של מצבי הקלט המתאימים כתנאים מקדימים, תחולק האחריות לשגיאות בצורה ברורה:

 

·        הלקוח הוא האחראי לקיום התנאים המקדימים. זו תהיה שגיאה של הלקוח לפנות למתודה במצבי קלט לא  

            מתאימים.

·        המתודה אחראית להגדרת התנאים המאוחרים ולדיווח על השגיאות המתרחשות בהתאם לתנאים אלו.

 

2.7.2 עיבוד שגיאות

הבה נתבונן בשגיאה שחייבת להיות מטופלת על ידי הבנאי, עבור כל הקצאה דינאמית של אובייקט.

המערכת עלולה שלא לאפשר הקצאת זיכרון מספיקה עבור האובייקט.

 

דרך טובה ליצור "אסון" היא כך:

 

X ConsX( .... )
    {
    X x = malloc( sizeof(struct t_X) );
    if ( x == NULL )
        {
          printf("Insuff mem\n"); 
        exit( 1 );
          }
    else
          .....
    }

 

לא רק שהודעת השגיאה היא כה סודית, עד שספק אם תעזור לאתר את מקור הבעיה (ההודעה צריכה להיות לפחות: "Insuff mem for X"!), התוכנית פשוט תיפסק, ככל הנראה תוך השארת המערכת במצב לא יציב ומעודכן חלקית. בגישה זו בעיות פוטנציאליות נוספות:

·        מה יקרה עם נבנה קוד זה לתוך תוכנית GUI מפורטת כלשהי, ללא סיפוק של יחידת "פלט סטנדרטי" ("standard output")? אנו עשויים אפילו לא לראות את ההודעה על יציאה מהתוכנית.

·        אנו עשויים להשתמש בקוד זה במערכת,  כגון מעבד משובץ (מחשב בקרה), אשר יתכן שאין לו דרך לעבד פלט של מחרוזת תווים כלל.

·        השימוש ב- exit מניח כי קיימת רמה גבוהה יותר בתוכנית, אשר תתפוס ותעבד את שגיאת הקוד.

 

            כחוק כללי - קלט ופלט אינם ניידים

 

פונקציה כגון printf תפיק הודעות שגיאה בחלון 'טרמינל' בתחנת העבודה המודרנית שלך. אך אם אתה מריץ תוכנית GUI כגון Netscape, היכן תקבל את ההודעות?

 

כך, אותה פונקציה עשויה שלא להפיק פלט של אבחון שימושי עבור שתי תוכניות שרצות בסביבות שונות באותו מעבד! כיצד נדאג ליעילות במקרה של העברת התוכנית כולה למערכת אחרת,

כגון מחשב מקינטוש או סביבת Windows?

 

לפני שנראה מה ניתן לעשות ב- ANSI C, הבה נבחן כיצד שפות אחרות מטפלות בבעיה זו.

 

 

 

המשך ל: חריגות ב- Ada                        חזור ל: תוכן עניינים