void aFoo1()

Download Report

Transcript void aFoo1()

‫הרצאה ‪05‬‬
‫חלוקת הפרויקט לקבצים‬
‫פקודות קדם מעבד והידור מותנה‬
‫קרן כליף‬
‫ביחידה זו נלמד‪:‬‬
‫‪ ‬חלוקת הפרויקט לקבצי ‪ header‬וקבצי ‪source‬‬
‫‪ ‬בעיות ב‪'include -‬ים כפולים‬
‫‪ ‬הידור מותנה‬
‫‪ ‬מאקרו‬
‫‪ ‬תהליך הקומפילציה‬
‫‪2‬‬
‫‪© Keren Kalif‬‬
‫יצירת קובץ ספריה‬
‫‪ ‬עד כה השתמשנו בפונקציות שקיבלנו משפת ‪C‬‬
‫‪ ‬כל פונקציה כזו נכתבה בספריה שאליה ביצענו ‪include‬‬
‫‪ ‬למשל כדי להשתמש בפונקציות של מחרוזות‪ ,‬עשינו‬
‫>‪#include <string.h‬‬
‫‪ ‬כדי לייצר ספריה משלנו נייצר ‪ 2‬קבצים חדשים‪:‬‬
‫‪ – <file_name>.h ‬קובץ זה יכלול את ה‪ prototypes -‬של‬
‫הפונקציות‪ ,‬מבנים ו‪'include -‬ים‪.‬‬
‫‪ ‬לקובץ זה נעשה ‪ include‬מהקובץ שירצה להשתמש בפונקציות המוגדרות בו‬
‫‪ – <file_name>.c ‬יכיל ‪ include‬לקובץ ה‪ header -‬התואם ויממש‬
‫את הפונקציות שבו‬
‫‪ include ‬לספריה שכתבנו יהיו בתוך "" (גרשיים) ולא בתוך <>‬
‫‪3‬‬
‫‪© Keren Kalif‬‬
)1( ‫דוגמא – ספריה המטפלת בתווים‬
// prototypes
int isSmallLetter(char);
int isCapitalLetter(char);
int isAlpha(char);
int isDigit(char);
character.h ‫הקובץ‬
© Keren Kalif
4
)2( ‫דוגמא – ספריה המטפלת בתווים‬
#include "charachter.h"
int isSmallLetter(char ch)
{
return (ch >= 'a' && ch <= 'z');
}
int isCapitalLetter(char ch)
{
return (ch >= 'A' && ch <= 'Z');
}
int isAlpha(char ch)
{
return (isSmallLetter(ch) || isCapitalLetter(ch));
}
int isDigit(char ch)
{
return (ch >= '0' && ch <= '9');
}
character.c ‫הקובץ‬
© Keren Kalif
5
)3( ‫דוגמא – ספריה המטפלת בתווים‬
#include <stdio.h>
#include "charachter.h"
main.c ‫הקובץ‬
void main()
{
char ch=0;
printf("Please enter a charachter: ");
ch = getchar();
printf("Is '%c' a digit? %d\n", ch, isDigit(ch));
printf("Is '%c' a small letter? %d\n", ch, isSmallLetter(ch));
printf("Is '%c' a capital letter? %d\n", ch, isCapitalLetter(ch));
printf("Is '%c' a letter? %d\n", ch, isAlpha(ch));
}
© Keren Kalif
6
‫ספריות שלנו ‪ -‬סיכום‬
‫‪ ‬ניתן לכתוב את כל הקוד בקובץ אחד‪ ,‬אבל אם אנחנו כותבים קוד‬
‫כללי‪ ,‬שיתכן ויהיה שימושי גם במקומו אחרים‪ ,‬נעדיף לחלק את‬
‫הקוד לקובץ ספריה נפרד‬
‫‪ ‬מי שירצה להשתמש בספריה שלנו‪ ,‬יתעניין מה יש לה להציע‪ ,‬ולא‬
‫איך היא מבצעת את הפעולות‪ ,‬וכך הוא יוכל להסתכל בקובץ‬
‫‪ header‬בלבד בו יש ריכוז של כל הפוקנציות‬
‫‪7‬‬
‫‪© Keren Kalif‬‬
include -‫ פעולת ה‬:‫תזכורת‬
‫) אשר‬preprocessor( ‫מעבד‬-‫ היא פקודת קדם‬include -‫ פעולת ה‬
‫ את תוכן הקובץ שאותו‬include ‫שותלת בקוד במקום כל פקודת‬
‫כללנו בפקודה‬
a.h
// prototypes
void aFoo1();
int aFoo2();
main.c
#include <stdio.h>
#include "a.h"
void main()
}
aFoo1();
aFoo2();
{
#include <stdio.h>
// prototypes
void aFoo1();
int aFoo2();
void main()
}
aFoo1();
aFoo2();
{
© Keren Kalif
8
a.h
// prototypes
void aFoo1();
int aFoo2();
include ‫הבעיתיות בפקודת‬
:‫ לקובץ מסוים יותר מפעם אחת‬include ‫ יתכן ונעשה‬
b.h
#include “a.h”
// prototypes
void bGoo1();
int bGoo2();
main.c
#include <stdio.h>
#include "a.h“
#include “b.h“
void main()
}
aFoo1();
bGoo1();
{
#include <stdio.h>
// prototypes
void aFoo1();
int aFoo2();
// prototypes
void aFoo1();
int aFoo2();
// prototypes
Void bGoo1();
int bGoo2();
‫נקבל שגיאה של‬
redefinition
‫מאחר והקומפיילר‬
‫רואה את ההצהרה‬
‫על הפונקציות‬
a.h -‫שמוגדרות ב‬
‫יותר מפעם אחת‬
void main()
}
aFoo1();
bGoo1();
{
© Keren Kalif
9
‫הפתרון‪ :‬הידור מותנה‬
‫‪ ‬ראינו בעבר את הפקודה ‪ #define‬לצורך הגדרת קבוע מסוים‬
‫‪ ‬פקודה זו מוסיפה את הקבוע שהוגדר לטבלת סימולים של‬
‫התוכנית במידה וטרם הוגדר‪ .‬במידה וכבר הוגדר דורסת את‬
‫ערכו‪.‬‬
‫‪ ‬ניתן גם לכתוב פקודת ‪ define‬ללא ערך‪ ,‬רק כדי להכניס קבוע‬
‫מסוים לטבלת הסימולים‬
‫‪ ‬ניתן לבדוק האם קבוע מסוים הוגדר בטבלת הסימולים בעזרת‬
‫הפקודה ‪ #ifdef‬או אם לא הוגדר בעזרת הפקודה ‪#ifndef‬‬
‫‪ ‬במידה והתנאי מתקיים‪ ,‬הקומפיילר יהדר את קטע הקוד‬
‫הבא עד אשר יתקל ב‪#endif -‬‬
‫‪10‬‬
‫‪© Keren Kalif‬‬
a.h
#ifndef __A_H
#define __A_H
// prototypes
void aFoo1();
int aFoo2();
#endif // __A_H
‫הפתרון עם הידור מותנה‬
b.h
#ifndef __B_H
#define __B_H
#include “a.h”
// prototypes
void bGoo1();
int bGoo2();
#endif // __B_H
main.c
#include <stdio.h>
#include "a.h“
#include “b.h“
void main()
}
aFoo1();
bGoo1();
{
:‫טבלת הסימולים‬
__A_H
__B_H
‫ לאחר‬main.c
preprocessor
#include <stdio.h>
// prototypes
void aFoo1();
int aFoo2();
// prototypes
void bGoo1();
int bGoo2();
void main()
}
aFoo1();
bGoo1();
{
main -‫כעת יש לנו ב‬
‫פעם אחת בלבד את‬
‫ההגדרות מכל קובץ‬
© Keren Kalif
11
‫מאקרו‬
,‫ כדי לבצע פעולה מסוימת‬define ‫ ניתן להשתמש בפקודת‬
‫ולא רק לצורך הגדרת קבועים‬
‫ מספרים‬2 ‫ הגדרת מאקרו המוצא מקסימום בין‬:‫ דוגמא‬
#include <stdio.h>
#include <stdio.h>
#define max(a, b) a > b ? a : b
‫מה שהקומפיילר רואה‬
void main()
void main()
:precompile ‫לאחר‬
{
{
printf("max is %d\n", 13 > 5 ? 13 : 5);
printf("max is %d\n", max(13, 5));
printf("max is %d\n", 5 > 13 ? 5 : 13);
printf("max is %d\n", max(5, 13));
{
{
© Keren Kalif
12
‫מאקרו ‪ -‬דגשים‬
‫‪ ‬בין שם המאקרו לסוגריים של הפרמטרים אסור שיהיה רווח‪,‬‬
‫אחרת מתקבלת שגיאת קומפילציה שלא ממש עוזרת להבנת‬
‫הבעיה‬
‫‪#define max(a, b) a > b ? a : b‬‬
‫‪ ‬בכתיבת המאקרו מאוד מומלץ בשימוש לעטוף כל פרמטר ב‪:)( -‬‬
‫)(‪void main‬‬
‫}‬
‫;))‪printf("sum is %d\n", (2+4) * (6/2‬‬
‫;))‪printf("sum is %d\n", 2+4 * 6 / 2‬‬
‫{‬
‫‪13‬‬
‫‪© Keren Kalif‬‬
‫)‪#define mult1(x, y) (x) * (y‬‬
‫‪#define mult2(x, y) x * y‬‬
‫מה שהקומפיילר רואה‬
‫לאחר ‪:precompile‬‬
‫)(‪void main‬‬
‫}‬
‫;))‪printf("sum is %d\n", mult1(2+4, 6/2‬‬
‫;))‪printf("sum is %d\n", mult2(2+4, 6/2‬‬
‫{‬
‫מאקרו ושימוש באופרטור ‪#‬‬
‫‪ ‬כאשר בתוך מאקרו שמים ‪ #‬לפני שם הפרמטר‪ ,‬הקומפיילר עוטף‬
‫אותו בגרשיים ולכן מתייחס לשמו ולא לערכו‬
‫‪ ‬הערת סוגריים‪ :‬הפקודה הבאה תקינה‪:‬‬
‫;)"‪printf("hi" " hello\n‬‬
‫‪ ‬דוגמא‪:‬‬
‫;)"‪#define PRINT(str) printf(#str "\n‬‬
‫)(‪main‬‬
‫}‬
‫;)"‪printf)“hello world” "\n‬‬
‫{‬
‫‪14‬‬
‫‪© Keren Kalif‬‬
‫)(‪main‬‬
‫}‬
‫;)‪PRINT(hello world‬‬
‫{‬
‫ דוגמא‬- # ‫מאקרו ושימוש באופרטור‬
#define PRINT_INT_VALUE(x)
printf(#x " = %d\n", x);
#define PRINT_VALUE(x, modifier) printf(#x " = %" #modifier "\n", x);
void main()
}
int value = 123;
char ch = 'a';
void main()
}
int value = 123;
char ch = 'a';
PRINT_INT_VALUE(value);
PRINT_VALUE(value, d);
PRINT_VALUE(ch, c);
PRINT_VALUE(ch, d);
{
printf("value" " = %d\n", value);
printf("value" " = %" "d" "\n", value);
printf("ch" " = %" "c" "\n", ch);
printf("ch" " = %" "d" "\n", ch);
{
© Keren Kalif
15
‫ההבדל בין מאקרו לפונקציה‬
‫‪ ‬ראינו כי ניתן לממש פונקציות בעזרת מאקרו‬
‫‪ ‬הבדלים בין פונקציה למאקרו ‪:‬‬
‫‪ ‬פיענוח המאקרו קורה בזמן קומפילציה (בשלב ה‪)preprocessor -‬‬
‫בעוד שקריאה לפונקציה קוראת בזמן ריצה‪ ,‬ויש לקפוץ למיקום‬
‫הפונקציה בזיכרון‬
‫‪ ‬שימוש במאקרו מנפח את ה‪ EXE -‬מאחר והוא נפרש ומשוכפל בכל‬
‫קריאה‪ ,‬בניגוד לפונקציה‬
‫‪ ‬לשימוש במאקרו יש חיסרון שלא ניתן לדבג אותו בעזרת ‪ ,F10‬וכן‬
‫הוא יותר קשה להבנה‪ ,‬כאשר הוא כולל הרבה פעולות‬
‫‪16‬‬
‫‪© Keren Kalif‬‬
‫דוגמא לשימוש בהידור מותנה ובמאקרו‬
‫‪ ‬נרצה לכתוב תוכנית המכילה הדפסות לצרכי ‪debug‬‬
‫‪ ‬נרצה לאפשר כמה סוגים של הדפסות‪ .‬למשל‪:‬‬
‫‪ ‬הדפסת ההודעה בציון שם הקובץ והשורה מהם נובעת‬
‫ההודעה‬
‫‪ ‬הדפסת ההודעה ללא נתונים נוספים‬
‫‪ ‬לא להדפיס הודעות בכלל‬
‫‪ ‬לא נרצה לעשות ‪'if‬ים בקוד שלנו‪ ,‬ולכן נשתמש בהידור מותנה‬
‫‪17‬‬
‫‪© Keren Kalif‬‬
#define DEBUG_WITH_DETAILS
‫דוגמא לשימוש‬
)1( ‫בהידור מותנה‬
#ifdef DEBUG_SIMPLE
#define PRINT(str) printf("%s\n", str);
#else
#ifdef DEBUG_WITH_DETAILS
#define PRINT(str) printf("%s (%d): %s\n", __FILE__, __LINE__, str);
#else
#define PRINT(str) ;
#endif
#endif
‫__ הוא מאקרו קיים לשם הקובץ הנוכחי‬FILE__
void foo()
}
PRINT("--> foo");
PRINT("<-- foo");
{
void main()
}
PRINT("--> Main");
foo();
PRINT("<-- Main");
{
‫__ הוא מאקרו קיים לשורה הנוכחית בקובץ‬LINE__
© Keren Kalif
18
#define DEBUG_SIMPLE
‫דוגמא לשימוש‬
)2( ‫בהידור מותנה‬
#ifdef DEBUG_SIMPLE
#define PRINT(str) printf("%s\n", str);
#else
#ifdef DEBUG_WITH_DETAILS
#define PRINT(str) printf("%s (%d): %s\n", __FILE__, __LINE__, str);
#else
#define PRINT(str) ;
#endif
#endif
void foo()
}
PRINT("--> foo");
PRINT("<-- foo");
{
void main()
}
PRINT("--> Main");
foo();
PRINT("<-- Main");
{
© Keren Kalif
19
‫דוגמא לשימוש‬
)3( ‫בהידור מותנה‬
#ifdef DEBUG_SIMPLE
#define PRINT(str) printf("%s\n", str);
#else
#ifdef DEBUG_WITH_DETAILS
#define PRINT(str) printf("%s (%d): %s\n", __FILE__, __LINE__, str);
#else
#define PRINT(str) ;
#endif
#endif
void foo()
}
PRINT("--> foo");
PRINT("<-- foo");
{
void main()
}
PRINT("--> Main");
foo();
PRINT("<-- Main");
{
© Keren Kalif
20
‫תהליך הקומפילציה‬
‫‪Disk‬‬
‫‪Editor‬‬
‫‪Disk‬‬
‫‪Preprocessor‬‬
‫‪Disk‬‬
‫‪Compiler‬‬
‫‪Disk‬‬
‫‪Linker‬‬
‫התוכנית נכתבת בעורך טקסטואלי ונכתבת לדיסק‬
‫קדם המעבד עובר על הקוד ומבצע החלפות נחוצות‬
‫(כל הפקודות המתחילות ב‪ ,# -‬כמו ‪ define‬ו‪include -‬‬
‫עבור כל קובץ ‪ ,c‬הקומפילר יוצר קובץ ‪ obj‬בשפת מכונה ושומר אותו‬
‫על הדיסק‪ .‬בשלב זה רק נבדקת תקינות הסינטקס בפונקציות‪.‬‬
‫ה‪ linker -‬קושר את קובץ ה‪ obj -‬עם הספריות‪ ,‬ויוצר קובץ ‪ exe‬המוכן‬
‫להרצה ונשמר בדיסק‪ .‬כלומר‪ ,‬מקשר בין קריאה לפונקציה‪ ,‬למימוש‬
‫שלה‪.‬‬
‫‪Primary Memory‬‬
‫‪Loader‬‬
‫‪..‬‬
‫‪..‬‬
‫‪..‬‬
‫‪Disk‬‬
‫‪Primary Memory‬‬
‫‪CPU‬‬
‫‪..‬‬
‫‪..‬‬
‫‪..‬‬
‫‪21‬‬
‫בעת ההרצה‪ ,‬טוענים את התוכנית מהדיסק לזיכרון הראשי‬
‫‪© Keren Kalif‬‬
‫עם הרצת התוכנית‪ ,‬ה‪ cpu -‬עובר על כל פקודה ומריץ אותה‬
‫דוגמא לשגיאת קומפילציה‬
#include <stdio.h>
void foo(int x)
}
printf("the number is %d\n");
{
void main()
{
for (i=0 ; i < 5 ; i++)
}
printf("%d ", i);
goo(i);
{
}
:‫נקבל את שגיאת הקומפילציה הבאה‬
error C2065: 'i' : undeclared identifier
:goo ‫הקומפיילר רק נותן אזהרה שהוא לא מוצא את‬
warning C4013: 'goo' undefined; assuming
extern returning int
‫ הקומפיילר לא ממשיך לתהליך לינקר‬,‫במידה ויש שגיאות קומפילציה‬
© Keren Kalif
22
‫דוגמא לשגיאת לינקר‬
#include <stdio.h>
void foo(int x)
}
printf("the number is %d\n");
{
void main()
{
int i;
for (i=0 ; i < 5 ; i++)
}
printf("%d ", i);
goo(i);
{
‫תוכנית זו מתקמפלת (אין שגיאות סינטקטיות בתוך‬
,‫הפונקציות) ולכן הקומפיילר עובר לתהליך הלינקר‬
:‫ומוציא את השגיאה הבאה‬
error LNK2019: unresolved external symbol
_goo referenced in function _main
}
© Keren Kalif
23
‫קומפילציה ביוניקס‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪24‬‬
‫כדי לקמפל את כל הפרוייקט שלנו ב‪ visual studio -‬לחצנו את‬
‫‪ build‬עבור הפרוייקט‪ ,‬התוצר היה קובץ ‪ EXE‬בספרית ‪DEBUG‬‬
‫כדי להעביר תהליך קומפילציה מלא הכולל לינקר בלינוקס‪:‬‬
‫]… ‪gcc >file.c< [file.c‬‬
‫התוצר להרצה יהיה הקובץ ‪out.a‬‬
‫אם רוצים ששם התוצר יהיה שונה‪:‬‬
‫>שם התוצר< ‪gcc >file.c< [file.c …] –o‬‬
‫כדי לקבל גם ‪ warnings‬יש לקמפל עם הדגל ‪-Wall‬‬
‫‪© Keren Kalif‬‬
‫קימפול ביוניקס‪ :‬רק קדם‪-‬מעבד‬
‫‪ ‬לעיתים מקבלים שגיאות שקשה לאתר את הבעיה‪:‬‬
‫‪ ‬קימפול שמראה את שלב הביניים שאותו המחשב מקמפל‪ ,‬היה‬
‫עוזר לפתור את הבעיה‪:‬‬
‫>‪gcc –E <file.c‬‬
‫‪ ‬התוצר של פקודה זו הוא רק פלט למסך‬
‫‪25‬‬
‫‪© Keren Kalif‬‬
‫קומפילציה ביוניקס‪ :‬קומפילציה בלבד‬
‫‪ ‬פקודת ‪ gcc‬מקמפלת‪ ,‬ואם הקימפול עבר בהצלחה מבצעת גם את‬
‫שלב הלינקר‬
‫‪ ‬התוצר של שלב הקומפילציה בלבד הוא קובץ עם סיומת ‪ o‬עבור כל‬
‫קובץ ‪ c‬שקימפלנו‬
‫‪ ‬התוצר של הלינקר הוא איחוד כל קבצי ה‪ obj -‬לכדי קובץ הרצה אחד‬
‫‪ ‬ניתן לקמפל את התוכנית ללא לינקר‪:‬‬
‫]…<‪gcc –c <file1.c> [<file2.c‬‬
‫‪ ‬בהמשך ניתן לקמפל רגיל את כל קבצי ה‪ o -‬לכדי קובץ הרצה‬
‫‪ ‬היתרון‪ :‬למשל כאשר אין לי גישה לקוד המקור וקיבלנו רק רכיבים‬
‫בודדים‬
‫‪ ‬כדי לראות את הפונקציות המוגדרות בקובץ ‪:o‬‬
‫‪nm <fileName>.o‬‬
‫‪26‬‬
‫‪© Keren Kalif‬‬
‫עבודה עם ספריות מוכנות‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪27‬‬
‫בעולם האמיתי נשתמש בספריות מוכנות שהורדנו מהאינטרנט ‪/‬‬
‫שקנינו מאישזהי חברה וכד'‬
‫ספריות כאלו לרוב לא יכילו את הקוד עצמו (כדי לא לחשוף את‬
‫האלגוריתם שלהם) ‪ ,‬אלא את הקוד מקודד באופן בינארי המוכן‬
‫לשימוש‪ ,‬ולא לקריאה‬
‫לצורך ההקבלה‪ :‬כאשר אנחנו קונים תוכנה מסויימת‪ ,‬אנחנו‬
‫מקבלים רק את קובץ ההרצה שלה‪ ,‬ולא את הקוד של איך‬
‫התוכנית כתובה‬
‫בניגוד לקבצי הרצה‪ ,‬לא יהיה בתוך הספריה פונקציית ‪main‬‬
‫אם קובץ עם סיומת ‪ o‬הוא תוצר קומפילציה בינארי של קובץ ‪c‬‬
‫אחד‪ ,‬אז ספריה הינה אוסף של כמה קבצים עם סיומת ‪( o‬למעשה‬
‫סוג של מארז)‬
‫‪© Keren Kalif‬‬
‫קומפילציה ביוניקס‪ :‬יצירת ספריה‬
‫‪ ‬כדי לייצר ספריה ביוניקס‪:‬‬
‫]… ‪>.a <file1>.o [<file2<.o‬שם הספריה שנרצה<‪ar r lib‬‬
‫‪ ‬דוגמא‪:‬‬
‫‪ar r libfunctions.a functions1.o functions2.o‬‬
‫‪ ‬שם הספריה חייב להתחיל ב‪ lib -‬ולהסתיים ב‪a -‬‬
‫‪ ‬ללקוחות שלנו נשלח‪:‬‬
‫‪ ‬את התוצר (קובץ עם סיומת ‪ )a‬המכיל באופן בינארי את כל מה שיש‬
‫בקבצי ה‪.o -‬‬
‫‪ ‬את קבצי ה‪ h -‬המכילים את הגדרות הפונקציות (לצרכי קומפילציה)‬
‫‪ ‬כדי לראות את ה‪'object -‬ים המוכלים בספריה‪:‬‬
‫>‪ar t <lib‬‬
‫‪28‬‬
‫‪© Keren Kalif‬‬
‫קומפילציה ביוניקס‪ :‬שימוש בספריה‬
‫‪ ‬כדי לקמפל את הקבצים שלנו עם קובץ ספרייה‪:‬‬
‫<‪h‬מיקום קבצי ה‪> -I< -‬שם הספריה<‪> –l‬מיקום הספריה<‪gcc <fileName>.c -L‬‬
‫‪ ‬דוגמא‪ ,‬עבור קימפול הקובץ ‪ main.c‬עם הספריה ‪libfamily.a‬‬
‫שנמצאת בתת הספריה ‪ ,familyLib‬שבה גם יש את קבצי ה‪:h-‬‬
‫‪gcc main.c -LfamilyLib -lfamily -IfamilyLib‬‬
‫‪ ‬הדגל ‪ -L‬מציין את מקום הספריה‬
‫‪ ‬יהיה ‪ .‬אם הספריה נמצאת באותו מיקום בו אנו מקמפלים‬
‫‪ ‬הדגל ‪ -I‬מציין את מיקום קבצי ה‪h -‬‬
‫‪29‬‬
‫‪© Keren Kalif‬‬
‫קומפילציה ב‪ :windows -‬יצירת ‪lib‬‬
‫‪ ‬נייצר פרוייקט שאינו מייצר ‪ ,EXE‬אלא ‪:LIB‬‬
‫‪30‬‬
‫‪© Keren Kalif‬‬
‫קומפילציה ב‪ :windows -‬שימוש ב‪lib -‬‬
‫‪ ‬נייצר פרוייקט רגיל‪ ,‬ונשנה את הגדרותיו‪:‬‬
‫שקול לדגל ‪ -I‬בקומפילציה ביוניקס‬
‫‪31‬‬
‫‪© Keren Kalif‬‬
‫קומפילציה ב‪ :windows -‬שימוש ב‪lib -‬‬
‫שקול לדגל ‪ -L‬בקומפילציה ביוניקס‬
‫‪32‬‬
‫‪© Keren Kalif‬‬
‫(‪)2‬‬
‫קומפילציה ב‪ :windows -‬שימוש ב‪lib -‬‬
‫שקול לדגל ‪ -l‬בקומפילציה ביוניקס‬
‫‪33‬‬
‫‪© Keren Kalif‬‬
‫(‪)3‬‬
‫קישור דינאמי לספריה לעומת קישור סטטי‬
‫‪ ‬הקישור שעשינו לספריה הינו קישור סטטי‬
‫‪ ‬כלומר‪ ,‬החלפת הספריה בספריה זהה‪ ,‬שרק מימוש הפונקציות שונה‪,‬‬
‫תדרוש קומפילציה מחדש של הקובץ שהשתמש בספריה‬
‫‪ ‬ניתן לבצע קישור דינאמי‬
‫‪ ‬כלומר‪ ,‬כל פעם שתהיה הרצה של התוכנית ויהיה שימוש בפונקציה‬
‫מהספריה‪ ,‬הקומפיילר יחפש את המימוש בזמן ריצה‬
‫‪ ‬לכן ניתן להחליף את הספריה ללא לקמפל מחדש‬
‫‪ ‬שימו לב‪ :‬החלפת הספריה משמע שהיא תכיל את אותן פונקציות‬
‫עם אותן חתימות בדיוק‪ ,‬רק המימושים שונים!‬
‫‪34‬‬
‫‪© Keren Kalif‬‬
‫מוזמנים ללמוד לבד את הנושא ‪‬‬
‫ביחידה זו למדנו‪:‬‬
‫‪ ‬חלוקת הפרויקט לקבצי ‪ header‬וקבצי ‪source‬‬
‫‪ ‬בעיות ב‪'include -‬ים כפולים‬
‫‪ ‬הידור מותנה‬
‫‪ ‬מאקרו‬
‫‪ ‬תהליך הקומפילציה‬
‫‪35‬‬
‫‪© Keren Kalif‬‬