You are on page 1of 3

‫‪Dvir Ben Asuli‬‬ ‫‪27/05/2020‬‬

‫נושא ‪ -5‬קבצים‪ ,‬פעולות על ביטים ו‪Preprocessor-‬‬


‫‪ -Preprocessor‬ראינו שלאחר שסיימנו לכתוב תוכנית‪ ,‬היא תחילה עוברת תהליך ‪ Preprocessing‬ורק לאחר מכן היא‬
‫הולכת לקומפיילר לבצע קומפילציה‪ ,‬ומשם ל‪ Linker-‬על מנת לקבל תוכנית שניתן להריץ‪.‬‬
‫התפקיד של שלב ה‪ Preprocessing-‬הוא לבצע החלפות פשוטות של קוד שמייעלות אותו‪ ,‬להחליט איזה קוד לקמפל‪ ,‬וכדומה‪.‬‬
‫למעשה‪ ,‬נתקלנו בזה בעבר עם פקודות ה‪ .#𝐼𝑛𝑐𝑙𝑢𝑑𝑒-‬בעצם כל פקודה שמתחילה ב‪ #-‬היא‬
‫פקודה שהולכת להתבצע בשלב ה‪ .Preprocessing-‬כך למשל שעשינו ‪ Include‬למשהו‪ ,‬זה אותו‬
‫ד ב ר כאילו עשינו ״העתק הדבק״ לכלשהו קוד )אותו קוד שאנחנו מצרפים( והוספנו אותו לקוד‬
‫שלנו להמשך קימפול‪.‬‬

‫דוגמא נוספת לשימוש ב‪ #-‬על מנת לכתוב פעולות שיתבצעו בשלב הקדם‪-‬עיבוד‬
‫זה שמגדירים קבועים‪ .‬בתחילת התוכנית ניתן להגדיר כלשהו שם שיכיל ערך‬
‫מסוים )למשל ערך מספרי(‪ ,‬והחל מאותה הנקודה כל פעם ששם זה יופיע אז זה‬
‫בעצם כאילו כתוב שם את אותו ערך שייחסו לו‪ .‬באופן דומה ניתן על ידי פקודה‬
‫בשלב מסוים לבטל הגדרה כזו של שם לערך מסוים‪ .‬בפועל מה שקורה בעת‬
‫קביעה שכזו‪ ,‬זה שאם למשל הגדרנו קבוע ‪ Pi‬עם הערך ‪ ,3.14‬בשלב הקדם ‪-‬עיבוד‬
‫ה‪ Preprocessor-‬יחליף כל מופע של המחרוזת ‪ Pi‬בערך המספרי ‪ ,3.14‬וכשנגיע לשלב‬
‫הקומפילציה זה כבר מה שהקומפיילר יראה‪.‬‬
‫במקרה יותר מורכב ניתן להגדיר מאקרו‪ ,‬שזה כמו להגדיר מראש פונקציה‪.‬‬
‫למשל בדוגמא שמובאת פה‪ ,‬כל פעם שה‪ Preprocessor-‬יראה את המחרוזת‬
‫)𝑥(𝑄𝑆 )עם כלשהו ארגומנט 𝑥‪ ,‬מה שהקומפיילר בעצם יראה זה את‬
‫ה מ ח ר ו ז ת 𝑥 ⋅ 𝑥‪ ,‬ו ה ו א י ק מ פ ל א ו ת ה ב ה ת א ם ‪.‬‬
‫חשוב לשים לב שלהגדיר מאקרו זה לא שקול בכלל ללהגדיר פונקציה‪ .‬כאשר אנחנו מגדירים מאקרו זה כמו להגדיר מימוש‬
‫של ״העתק‪-‬הדבק״ לא מתוחכם במיוחד שמשנה את מה שהקומפיילר יראה כאשר הוא יתקל בביטוי שרשמנו‪ .‬צריך להיזהר‬
‫עם זה כדי שלא ייווצרו שגיאות‪.‬‬
‫שפת 𝐶 גם מכילה מספר מאקרוים מוגדרים מראש‪ ,‬שנוכל לרשום אותם ישירות בתוכנית שלנו בלי להגדיר אותם ומה‬
‫שהקומפיילר יראה זה את הערך המיוחד שהם מייצגים‪.‬‬

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

‫‪1‬‬ ‫‪Tel-Aviv University‬‬


‫‪Dvir Ben Asuli‬‬ ‫‪27/05/2020‬‬
‫הפונקציה ‪ fopen‬מקבלת בתור ארגומנט את הכתובת ‪ Directory‬של הקובץ אותו אנחנו רוצים לפתוח‪ ,‬ותו נוס‪ ,‬שאומר מה‬
‫אנחנו רוצים לעשות עם הקובץ‪:‬‬
‫‪ -‬אם אנחנו רוצים לקרוא מהקובץ כותבים ‪.r‬‬
‫‪ -‬אם אנחנו רוצים לכתוב בקובץ כותבים ‪.w‬‬
‫אם אנחנו רוצים להוסיף בתחתית קובץ כותבים 𝑎‪.‬‬ ‫‪-‬‬
‫מ ה ש פ ו נ ק צ י ה ז ו מ ח ז י ר ה ז ה מ צ ב י ע לקובץ‪ ,‬כלומר משתנה שיכיל מעשית את הכתובת לאכסון של הקובץ בזיכרון ובאמצעות‬
‫הסימן * נוכל לגשת לקובץ עצמו ולשחק איתו‪.‬‬
‫באופן דומה בסוף הפעולה עם הקובץ יש לסגור אותו על ידי פעולת ‪ ,fclose‬שמקבלת את אותו משתנה הצבעה שפתחנו‬
‫בהתחלה‪ .‬פונקציית הסגירה היא פונקציה שמחזירה מספר ‪ 0‬אם הסגירה התבצעה בהצלחה או שגיאת ‪ −1‬במידה ולא‪.‬‬
‫על מנת להשתמש בפקודות אלו חייב לעשות ‪ Include‬לחבילה ‪.stdio.h‬‬
‫למשל נסתכל על הדוגמא פה‪:‬‬
‫תחילה אנחנו יוצרים אובייקט הצבעה לאובייקט מסוג ‪ ,FILE‬שיכיל את הקובץ‪.‬‬
‫למשתנה קוראים ‪ ifp‬והוא ישמש כמצביע‪.‬‬
‫אנחנו מעבירים למשתנה ‪ ifp‬את ערך ההחזרה של הפונקציה ‪ fopen‬עבור כלשהו‬
‫קובץ שקראנו‪ ,‬וכעת ‪ ifp‬יכיל את הכתובת לייצוג קובץ זה בזיכרון‪.‬‬
‫כאשר נרצה להשתמש בקובץ‪ ,‬ניגש אליו באמצעות המצביע ‪.*ifp‬‬
‫נשים לב שכאשר אנחנו רוצים לסגור אותו אנחנו מעבירים לפונקציה רק את ‪ifp‬‬
‫עצמו‪ ,‬ובתוך ההגדרה הפנימית של הפונקציה מתייחסים אליו כמצביע‪ .‬באופן‬
‫דומה‪ ,‬הרבה פונקציות שמוגדרות על קבצים גם הן משתמשות ישירות ב‪ ifp-‬שכן בתוכה הוא מוגדר כמצביע‪.‬‬

‫פעולות ‪ -Bitwise‬פעולות שעובדות על הייצוג הבינארי של משתנים‪ ,‬ולא על הערך המספרי שלהם‪.‬‬
‫למשל‪ ,‬בדוגמא הבאה הגדרנו שני משתנים‪ ,‬האחד עם ערך ‪ 33333‬והשני עם ערך ‪ .−77777‬כעת פעולות ה‪ Bitwise-‬לא‬
‫יתייחסו לערכים מספריים אלו של המשתנים אלא יתייחסו לייצוג ה ב י נ א ר י ש ל כ ל מ ס פ ר ב ז י כ ר ו ן ש ל ה מ ח ש ב ‪:‬‬

‫למשל בשורה השלישית‪ ,‬מה שאנחנו מבצעים זה פעולת ‪ AND‬לוגית ביט מול ביט במחרוזות של המספרים‪ .‬המספר שייווצר‬
‫בסוף‪ ,32805 ,‬אין לו שום קשר לערכים המספריים שראינו בהתחלה למשתנים‪ ,‬אלא הוא פשוט המספר שהייצוג הבינארי‬
‫שלו זה מה שמתקבל מפעולת ‪ Bitwise-And‬על שתי המחרוזות‪.‬‬
‫השורה הרביעית מתארת פעולת 𝑅𝑂𝑋‪ ,‬החמישית ‪ ,Or‬השישית משתמש גם ב‪ Not -‬וכדומה‪.‬‬
‫נזכור כי בייצוג הבינארי של מספרים בזיכרון המחשב משתמשים בשיטת המשלים ל‪ .2-‬לפי שיטה זו‪ ,‬אם הביט השמאלי‬
‫ביותר של המחרוזת הוא ״‪1‬״ אז המחרוזת מייצגת מספר שלילי ואם הוא ״‪0‬״ אז היא מייצגת מספר חיובי‪.‬‬

‫‪2‬‬ ‫‪Tel-Aviv University‬‬


‫‪Dvir Ben Asuli‬‬ ‫‪27/05/2020‬‬
‫פעולות נוספות שניתן לבצע על הייצוג הבינארי של מחרוזות הן פעולות ‪ -Shift‬כלומר להזיז את כל הביטים של המחרוזת‬
‫מספר מסוים של צעדים ימינה או שמאלה‪.‬‬

‫נזכור כי כל הזזה שמאלה מייצגת הכפלה של הערך המספרי של המחרוזת פי ‪ ,2‬וכל הזזה ימינה מייצגת הכפלה של הערך‬
‫!‬
‫ה מ ס פ ר י ש ל ה מ ח ר ו ז ת פ י "‪.‬‬

‫‪3‬‬ ‫‪Tel-Aviv University‬‬

You might also like