C/C++ מדריכי
C הקדמה לתכנות ב
C++ הקדמה להיררכית מחלקות ב הצגה מזורזת :C++ הבנת דף הבית

שיעור 7: ספריות C ו makefiles

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

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

#include <stdio.h>  
 
#define MAX 10 
 
int a[MAX]; 
int rand_seed=10; 
 
int rand()  
/* from K&R - produces a random number between 0 and 32767.*/  
{    
    rand_seed = rand_seed * 1103515245 +12345;    
    return (unsigned int)(rand_seed / 65536) % 32768;  
} 
 
void main()  
{    
    int i,t,x,y;
  
    /* fill array */    
    for (i=0; i < MAX; i++)    
    {      
        a[i]=rand();      
        printf("%d\n",a[i]);    
    }
  
    /* bubble sort the array */    
    for (x=0; x < MAX-1; x++)      
        for (y=0; y < MAX-x-1; y++)        
            if (a[y] > a[y+1])        
            {  
                t=a[y];  
                a[y]=a[y+1];  
                a[y+1]=t;        
            } 
 
    /* print sorted array */    
    printf("--------------------\n");    
    for (i=0; i < MAX; i++)     
        printf("%d\n",a[i]); 
} 

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

קח את קוד מיון הבועות, והשתמש במה שלמדת בשיעור 6 כדי ליצור ממנו פונקציה. כיוון שהן המערך a והן הקבוע MAX הם גלובליים, הפונקציה אותה תיצור לא צריכה לקבל פרמטרים, ולא צריכה להחזיר תוצאה. בכל אופן, עליך להשתמש במשתנים מקומיים ל x, y ו t.

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

#include <stdio.h> 
 
#define MAX 10 
 
int a[MAX]; 
int rand_seed=10; 
 
int rand() /* from K&R - returns random number between 0 and 32767.*/  
{    
    rand_seed = rand_seed * 1103515245 +12345;    
    return (unsigned int)(rand_seed / 65536) % 32768;  
}
  
void bubble_sort(int m)  
{    
    int x,y,t; 
     for (x=0; x < m-1; x++)      
        for (y=0; y < m-x-1; y++)        
            if (a[y] > a[y+1])        
            {  
                t=a[y];  
                a[y]=a[y+1];  
                a[y+1]=t;        
            } 
}
  
void main()  
{    
    int i,t,x,y; 
    /* fill array */    
    for (i=0; i < MAX; i++)    
    {      
        a[i]=rand();      
        printf("%d\n",a[i]);    
    } 
    bubble_sort(MAX); 
    /* print sorted array */    
    printf("--------------------\n");    
    for (i=0; i < MAX; i++)      
        printf("%d\n",a[i]); 
}

ניתן גם להכליל את הפונקציה bubble_sort עוד יותר באמצעות העברת a והגודל של a כפרמטרים:

bubble_sort(int m, int a[])

משמעות שורה זו, "קבל את מערך השלמים a מכל גודל כפרמטר". דבר בגוף פונקצית ה bubble_sort לא צריך להשתנות. כדי לקרוא לפונקציה שנה את הקריאה ל:

bubble_sort(MAX, a);

שים לב שלא נעשה שימוש ב a& למרות שהמיון ישנה את a. הסיבה לכך תובהר בשיעור 10.

יצירת ספריה

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

כל ספריה מורכבת משני חלקים: קובץ כותרת (header file) וקובץ קוד ממשי. קובץ הכותרת, שבדרך כלל מצוין בסיומת h., מכיל מידע על הספריה שתוכניות שמשתמשות בה צריכות לדעת. באופן כללי, קובץ הכותרת מכיל קבועים וטיפוסים, ביחד עם כותרות לפונקציות הזמינות בספריה. הקלד את קובץ הכותרת הבא ושמור אותו לקובץ בשם util.h.

/* util.h */
extern int rand(); 
extern void bubble_sort(int,int []);

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

הכנס את הקוד הבא לקובץ בשם util.c.

/* util.c */
#include "util.h" 
 
int rand_seed=10; 
 
int rand()  
/* from K&R - produces a random number between 0 and 32767.*/ 
{    
    rand_seed = rand_seed * 1103515245 +12345;    
    return (unsigned int)(rand_seed / 65536) % 32768;  
} 
  
void bubble_sort(int m,int a[])  
{    
    int x,y,t; 
     for (x=0; x < m-1; x++)      
        for (y=0; y < m-x-1; y++) 
            if (a[y] > a[y+1])        
            {  
                t=a[y];  
                a[y]=a[y+1];  
                a[y+1]=t;        
            }  
}

שים לב שהקובץ מכליל את קובץ הכותרת שלו (util.h) ושהוא משתמש במרכאות במקום בסמלים > ו < בהם משתמשים רק לספריות מערכת. כפי שניתן לראות, זה נראה כמו קוד C רגיל. שים לב שהמשתנה rand_seed, בגלל שהוא לא נמצא בקובץ הכותרת, לא יכול להיראות או להשתנות על ידי תוכנית שמשתמשת בספריה זו. דבר זה נקרא הסתרת מידע. הוספת המילה static לפני int כופה את ההסתרה לחלוטין.

הדפס את פונקצית ה main הבאה לקובץ בשם main.c.

#include <stdio.h>  
#include "util.h" 
 
#define MAX 10  
 
int a[MAX];  
 
void main()  
{    
    int i,t,x,y; 
    /* fill array */    
    for (i=0; i < MAX; i++)    
    {      
        a[i]=rand();      
        printf("%d\n",a[i]);    
    } 
 
    bubble_sort(MAX,a); 
 
    /* print sorted array */   
    printf("--------------------\n");    
    for (i=0; i < MAX; i++)      
        printf("%d\n",a[i]); 
} 

קוד זה מכליל את ספריית השירות. התועלת העיקרית בשימוש בספריה היא שהקוד בפונקצית ה main הוא הרבה יותר קצר.

הידור והרצה עם ספריה

כדי להדר את הספריה, הדפס את השורה הבאה בשורת הפקודה (בהנחה שאתה משתמש ב UNIX):

cc -c -g util.c

ה c- גורם למהדר ליצור קובץ יעד (object file) לספרייה. קובץ היעד מכיל את קוד המכונה של הספריה. הוא לא יכול להתבצע עד שהוא לא מקושר לקובץ תכנית (program file) שמכיל את פונקצית ה main. קוד המכונה שוכן בקובץ נפרד בשם util.o.

כדי להדר את פונקצית ה main, הדפס את השורה שלהלן:

cc -c -g main.c

שורה זו יוצרת קובץ בשם main.o שמכיל את קוד המכונה לפונקצית ה main. כדי ליצור את הקובץ הניתן להרצה (executable) הסופי שמכיל את קוד המכונה לכל התוכנית, קשר את שני קבצי היעד על ידי הדפסת:

cc -o main main.o util.o

שמקשר את main.o ו util.o כדי ליצור קובץ ניתן להרצה בשם main. כדי להריץ אותו, הקש main. זה יכול להיות מסורבל להדפיס את כל שורות ה cc שוב ושוב, במיוחד אם אתה עושה הרבה שינויים בקוד ויש בו מספר ספריות. כלי ה make פותר בעיה זו. אתה יכול להשתמש ב makefile הבא כדי להחליף את סדרת ההידורים הנ"ל:

main: main.o util.o  
        cc -o main main.o util.o 
main.o: main.c util.h 
        cc -c -g main.c 
util.o: util.c util.h  
        cc -c -g util.c

הכנס זאת לקובץ בשם makefile, והקש make כדי לבנות את הקובץ שניתן להרצה. שים לב שעליך להקדים את כל שורות ה cc ב tab. (שמונה רווחים לא יספיקו - זה חייב להיות tab. כל יתר השורות צריכות להיות מיושרות שמאלה).

ה makefile מכיל שני סוגים של שורות. השורות שמופיעות מיושרות לשמאל הן שורות תלות. השורות שמוקדמות ב tab הן שורות ביצוע, שיכולות להכיל כל פקודת UNIX הגיונית. שורת תלות אומרת שקובץ כלשהו תלוי בסדרה אחרת של קבצים. לדוגמא, main.o:main.c util.h משמעותה שהקובץ main.o תלוי בקבצים main.c ו util.h. אם מי משני הקבצים האלו משתנה, שור(ו)ת הביצוע שאחריהן צריכות להתבצע כדי ליצור מחדש את main.o.

יש לציין שהקובץ הניתן להרצה הסופי שנוצר על ידי כל ה makefile הוא main, בשורה 1 ב makefile. התוצאה הסופית של ה makefile צריכה תמיד להיות בשורה 1, שב makefile הזה אומרת שהקובץ main תלוי ב main.o ו util.o. אם מי משני אלו משתנה, בצע את השורה cc -o main main.o util.o כדי ליצור מחדש את main.

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




לדף הראשון

<< לדף הקודם

לדף הבא >>