תפריט English Ukrainian רוסי עמוד הבית

ספרייה טכנית בחינם לחובבים ואנשי מקצוע ספריה טכנית בחינם


הערות הרצאה, דפי רמאות
ספרייה חינם / מדריך / הערות הרצאה, דפי רמאות

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

הערות הרצאה, דפי רמאות

מדריך / הערות הרצאה, דפי רמאות

הערות למאמר הערות למאמר

תוכן העניינים

  1. מבוא למדעי המחשב (אינפורמטיקה. מידע. הצגה ועיבוד מידע. מערכות מספרים. ייצוג מספרים במחשב. מושג פורמלי של אלגוריתם)
  2. שפת פסקל (מבוא לפסקל. נהלים ופונקציות סטנדרטיות. אופרטורים של פסקל)
  3. נהלים ותפקודים (המושג של אלגוריתם עזר. נהלים בפסקל. פונקציות בפסקל. תיאורים מקדימים וחיבור של תתי שגרות. הנחיות)
  4. תתי שגרות (פרמטרים שגרתיים. סוגי פרמטרים של תת-שגרה. סוג מחרוזת בפסקל. נהלים ופונקציות למשתנים מסוג מחרוזת. רשומות. סטים)
  5. קבצים (קבצים. פעולות קבצים. מודולים. סוגי מודולים)
  6. זיכרון דינמי (סוג נתוני התייחסות. זיכרון דינמי. משתנים דינמיים. עבודה עם זיכרון דינמי. מצביעים לא מודפסים)
  7. מבני נתונים מופשטים (מבני נתונים מופשטים. ערימות. תורים)
  8. מבני נתונים של עצים (מבני נתוני עצים. פעולות על עצים. דוגמאות ליישום פעולות)
  9. סופר (המושג של גרף. שיטות לייצוג גרף. ייצוג של גרף לפי רשימת שכיחות. אלגוריתם מעבר עומק-ראשון לגרף. ייצוג גרף כרשימה של רשימות. רוחב-ראשון אלגוריתם מעבר לגרף )
  10. סוג נתוני אובייקט (סוג אובייקט בפסקל. מושג האובייקט, התיאור והשימוש בו. ירושה. יצירת מופעים של אובייקטים. רכיבים והיקף)
  11. שיטות (שיטות. קונסטרוקטורים ומשמידים. משמידים. שיטות וירטואליות. שדות נתוני אובייקט ופרמטרים צורניים של שיטה)
  12. תאימות מסוג אובייקט (אנקפסולציה. אובייקטים הניתנים להרחבה. תאימות לסוג אובייקט)
  13. אסמבלר (על אסמבלר. מודל תוכנת מיקרו-מעבד. אוגרי משתמשים. אוגרי מטרה כלליים. אוגרי פלחים. אוגרי סטטוס ובקרה)
  14. רישומים (אוגרי מערכת מיקרו-מעבד. אוגרי בקרה. אוגרי כתובות מערכת. אוגרי באגים)
  15. תוכניות הרכבה (מבנה תוכנית ה-Assembler. תחביר ה-Assembler. אופרטורים השוואה. אופרטורים והקדימות שלהם. הנחיות הגדרת מקטעים מפושטות. מזהים שנוצרו על ידי הוראת MODEL. מודלים של זיכרון. שינויי מודל זיכרון)
  16. מבני הוראות הרכבה (מבנה של הוראת מכונה. שיטות לציון אופרנדים של הוראות. שיטות התייחסות)
  17. פקודות (פקודות העברת נתונים. פקודות אריתמטיות)
  18. פקודות העברת בקרה (פקודות לוגיות. טבלת אמת לשלילה לוגית. טבלת אמת עבור OR כוללנית לוגית. טבלת אמת עבור AND לוגית. טבלת אמת עבור OR בלעדי לוגית. משמעות הקיצורים בשם הפקודה jcc. רשימת פקודות קפיצה מותנית לפקודה. קפיצה מותנית פקודות ודגלים)

הרצאה מס' 1. מבוא למדעי המחשב

1. מדעי המחשב. מֵידָע. ייצוג ועיבוד מידע

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

במדעי המחשב, למושג בסיסי כמו מידע יש משמעויות שונות:

1) הצגה רשמית של צורות מידע חיצוניות;

2) משמעות מופשטת של מידע, תוכנו הפנימי, סמנטיקה;

3) יחס של מידע לעולם האמיתי.

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

אחד התיאורים המתמטיים של מידע הוא הייצוג שלו בצורה של פונקציה y =f(x, t), כאשר t הוא זמן, x היא נקודה בשדה מסוים שבה נמדד ערכו של y. בהתאם לפרמטרים של פונקציית הצ'י (ניתן לסווג מידע.

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

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

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

הערך שיכול להיות מיוצג על ידי סמל של האלפבית הבינארי נקרא יחידת המידע המינימלית או סיביות. רצף של 8 ביטים - בתים. אלפבית המכיל 256 רצפים שונים של 8 סיביות נקרא אלפבית בתים.

כסטנדרט כיום במדעי המחשב, מאומץ קוד שבו כל תו מקודד ב-1 בייט. יש גם אלפביתים אחרים.

2. מערכות מספרים

מערכת מספרים היא מערכת כללים למתן שמות וכתיבת מספרים. ישנן מערכות מספר מיקום ולא מיקומי.

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

3. ייצוג מספרים במחשב

מעבדי 32 סיביות יכולים לעבוד עם עד 232-1 זיכרון RAM, וניתן לכתוב כתובות בטווח 00000000 - FFFFFFFF. עם זאת, במצב אמיתי, המעבד פועל עם זיכרון של עד 220-1, והכתובות נופלות בטווח 00000 - FFFFF. ניתן לשלב בייטים של זיכרון לשדות באורך קבוע ומשתנה כאחד. מילה היא שדה באורך קבוע המורכב מ-2 בתים, מילה כפולה היא שדה של 4 בתים. כתובות שדות יכולות להיות זוגיות או אי-זוגיות, כאשר כתובות זוגיות מבצעות פעולות מהר יותר.

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

מספרים שלמים בינאריים מיוצגים בהשלמה של שניים, ומספרים של נקודות קבועות מיוצגים בהשלמה של שניים. יתרה מכך, אם מספר תופס 2 בתים, מבנה המספר נכתב על פי הכלל הבא: הספרה המשמעותית ביותר מוקצית לסימן המספר, והשאר - לספרות הבינאריות של המספר. הקוד המשלים של מספר חיובי שווה למספר עצמו, וניתן לקבל את הקוד המשלים של מספר שלילי באמצעות הנוסחה הבאה: x = 10i - \x\, כאשר n היא קיבולת הספרות של המספר.

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

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

4. מושג פורמלי של אלגוריתם

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

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

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

הפונקציות הבסיסיות והאלגוריתמים הנלווים להן יכולות להיות:

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

2) פונקציית הזהות של n משתנים בלתי תלויים בצורת ψni. לאחר מכן, אם הסימן של הפונקציה הוא ψni, אז יש לקחת את הערך של הפונקציה כערך של הארגומנט i-th, בספירה משמאל לימין;

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

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

הרצאה מס' 2. שפת פסקל

1. מבוא לשפת פסקל

הסמלים הבסיסיים של השפה - אותיות, מספרים ותווים מיוחדים - מרכיבים את האלפבית שלה. שפת פסקל כוללת את קבוצת הסמלים הבסיסיים הבאים:

1) 26 אותיות קטנות לטיניות ו-26 אותיות רישיות לטיניות:

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

אבגדהוזחטיכלמנסעפצקרשת;

2) _ (קו תחתון);

3) 10 ספרות: 0123456789;

4) סימני פעולה:

+ - x / = <> < > <= >= := @;

5) מגבילים:

., ' ( ) [ ] (..) { } (* *).. : ;

6) מפרטים: ^ # $;

7) מילות שירות (שמורה):

ABSOLUTE, ASSEMBLER, AND, RRAY, ASM, BEGIN, CASE, CONST, CONSTRUCTOR, DESTRUCTOR, DIV, DO, DOWNTO, ELSE, END, EXPORT, EXTERNAL, FAR, FILE, FOR, FORWARD, FUNCTION, GOTO, IF, IMPLEMENT, IN, INDEX, HERITED, INLINE, INTERFACE, Interrupt, LABEL, LIBRARY, MOD, NAME, NIL, NEAR, NOT, OBJECT, OF, OR, Packed, PRIVATE, PROCEDURE, PROGRAM, PUBLIC, RECORD, REPEAT, RESIDENT, SET, SHL, SHR, STRING, THEN, TO, TYPE, UNIT, TILL, USES, VAR, VIRTUAL, WHILE, WITH, XOR.

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

הקלד קונספט עבור נתונים

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

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

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

2) ניתן לקבוע את סוג הערך שניתן על ידי קבוע, משתנה או ביטוי לפי צורתם או תיאורם;

3) כל פעולה או פונקציה דורשת ארגומנטים מסוג קבוע ומפיקה תוצאת סוג קבוע.

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

הסוג מגדיר:

1) ערכים אפשריים של משתנים, קבועים, פונקציות, ביטויים השייכים לסוג מסוים;

2) הצורה הפנימית של הצגת נתונים במחשב;

3) פעולות ופונקציות שניתן לבצע על ערכים השייכים לסוג מסוים.

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

ישנם סוגי נתונים סקלרים ומובנים בפסקל. טיפוסים סקלרים כוללים סוגים סטנדרטיים וסוגים מוגדרי משתמש. סוגים סטנדרטיים כוללים מספר שלם, אמיתי, תו, בוליאני וסוגי כתובות.

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

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

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

בנוסף לאלו המפורטים, פסקל כולל שני סוגים נוספים - פרוצדורלי ואובייקט.

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

1) חישובים בסוגריים;

2) חישוב ערכי פונקציה;

3) פעולות לא דומות;

4) פעולות *, /, div, mod, ו;

5) פעולות +, -, או, xor;

6) פעולות יחסיות =, <>, <, >, <=, >=.

ביטויים הם חלק מאופרטורי שפות פסקל רבים ויכולים להיות גם ארגומנטים לפונקציות מובנות.

2. נהלים ופונקציות סטנדרטיות

פונקציות אריתמטיות

1.Function Abs(X);

מחזירה את הערך המוחלט של הפרמטר.

X הוא ביטוי מסוג אמיתי או שלם.

2. פונקציה ArcTan(X: Extended): Extended;

מחזירה את טנגנס הקשת של הארגומנט.

X הוא ביטוי מסוג אמיתי או שלם.

3. פונקציה exp(X: Real): Real;

מחזירה את המעריך.

X הוא ביטוי מסוג אמיתי או שלם.

4.Frac(X: Real): אמיתי;

מחזירה את החלק השברי של הארגומנט.

X הוא ביטוי מסוג אמיתי. התוצאה היא החלק השבר של X, כלומר.

Frac(X) = X-Int(X).

5. פונקציה Int(X: Real): Real;

מחזירה את החלק השלם של הארגומנט.

X הוא ביטוי מסוג אמיתי. התוצאה היא החלק השלם של X, כלומר X מעוגל לאפס.

6. פונקציה Ln(X: Real): Real;

מחזירה את הלוגריתם הטבעי (Ln e = 1) של ביטוי מסוג אמיתי X.

7. Function Pi: מורחב;

מחזירה את הערך Pi, המוגדר כ-3.1415926535.

8.Function Sin(X: Extended): Extended;

מחזירה את הסינוס של הארגומנט.

X הוא ביטוי מסוג אמיתי. Sin מחזיר את הסינוס של זווית X ברדיאנים.

9.Function Sqr(X: Extended): Extended;

מחזירה את הריבוע של הארגומנט.

X הוא ביטוי של נקודה צפה. התוצאה היא מאותו סוג של X.

10.Function Sqrt(X: Extended): Extended;

מחזירה את השורש הריבועי של הארגומנט.

X הוא ביטוי של נקודה צפה. התוצאה היא השורש הריבועי של X.

נהלים ופונקציות של המרת ערך

1. הליך Str(X [: Width [: Decimals]]; var S);

ממירה את המספר X לייצוג מחרוזת לפי

אפשרויות עיצוב רוחב ועשרוניות. X הוא ביטוי מסוג אמיתי או שלם. רוחב ועשרוניות הם ביטויים מסוג מספר שלם. S הוא משתנה מסוג String או מערך תווים עם סיומת Null אם התחביר המורחב מותר.

2. פונקציה Chr(X: Byte): Char;

מחזירה את התו עם X סידורי בטבלת ASCII.

3. פונקציה גבוהה (X);

מחזירה את הערך הגדול ביותר בטווח של הפרמטר.

4.FunctionLow(X);

מחזירה את הערך הקטן ביותר בטווח הפרמטרים.

5 FunctionOrd(X): Longint;

מחזירה את הערך הסידורי של ביטוי מסוג ממוספר. X הוא ביטוי מסוג מסופר.

6. סיבוב פונקציות (X: מורחב): Longint;

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

7. פונקציה Trunc(X: Extended): Longint;

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

8. נוהל Val(S; var V; var Code: שלם);

ממירה מספר מערך מחרוזת S למספר

ייצוג V. S - ביטוי מסוג מחרוזת - רצף של תווים שיוצר מספר שלם או ממשי. אם ביטוי S אינו חוקי, האינדקס של התו הלא חוקי מאוחסן במשתנה Code. אחרת הקוד מוגדר לאפס.

נהלים ופונקציות של ערך רגיל

1. הליך Dec(varX [; N: LongInt]);

מחסיר אחד או N מהמשתנה X. Dec(X) מתאים ל-X:= X - 1, ו-Dec(X, N) מתאים ל-X:= X - N. X הוא משתנה מסוג מסופר, או מסוג PChar אם התחביר המורחב מותר, ו-N הוא ביטוי מסוג מספר שלם. הליך Dec מייצר קוד אופטימלי והוא שימושי במיוחד בלולאות ארוכות.

2. Procedure Inc(varX [; N: LongInt]);

מוסיף אחד או N למשתנה X. X הוא משתנה מסוג מסופר או מסוג PChar אם התחביר המורחב מותר, ו-N הוא ביטוי מסוג אינטגרלי. Inc (X) תואם את ההוראה X:= X + 1, ו- Inc (X, N) תואם את ההוראה X:= X + N. הליך Inc מייצר קוד אופטימלי והוא שימושי במיוחד בלולאות ארוכות.

3. FunctionOdd(X: LongInt): בוליאנית;

מחזירה True אם X הוא מספר אי-זוגי, False אחרת.

4.FunctionPred(X);

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

5 פונקציה Succ(X);

מחזירה את ערך הפרמטר הבא. X הוא ביטוי מסוג מסופר. התוצאה היא מאותו סוג.

3. אופרטורי שפת פסקל

מפעיל מותנה

הפורמט של ההצהרה המותנית המלאה מוגדר כדלקמן: אם B אז SI אחרת S2; כאשר B הוא מצב מסתעף (קבלת החלטות), ביטוי לוגי או יחס; SI, S2 - הצהרת הפעלה אחת, פשוטה או מורכבת.

בעת ביצוע משפט מותנה, תחילה מעריכים את הביטוי B, ואז מנתחים את התוצאה שלו: אם B נכון, אז מבוצעת המשפט S1 - הענף של אז, והמשפט S2 מדלגים; אם B הוא שקר, אז משפט S2 - הענף else מבוצע, ומשפט S1 מדלגים.

יש גם צורה מקוצרת של האופרטור המותנה. כתוב כך: אם ב' אז ס'.

בחר הצהרה

מבנה המפעיל הוא כדלקמן:

מקרים של

c1: הוראה1;

c2: הוראה2;

...

cn: instructionN;

הוראה אחרת

הסוף;

כאשר S הוא ביטוי מסוג רגיל שהערך שלו מחושב;

с1, с2..., сп - קבועים מסוג סידורי איתם מושווים ביטויים

ס; instruction1,..., instructionN - אופרטורים אשר זה שהקבוע שלו תואם את ערכו של הביטוי S מבוצע;

instruction - משפט שמתבצע אם הערך של ביטוי Sylq לא תואם אף אחד מהקבועים c1, c2.... cn.

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

משפט לולאה עם פרמטר

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

תצוגה כללית של הצהרת for:

עבור <מונה לולאה> := <ערך התחלה> ל-<ערך סיום> לעשות <הצהרה>;

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

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

הצהרת לולאה עם תנאי מוקדם

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

בעוד ב' לעשות ס;

כאשר B הוא תנאי לוגי, אשר אמיתותו נבדקת (זהו תנאי לסיום הלולאה);

S - גוף לולאה - משפט אחד.

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

הצהרת לולאה עם postcondition

במשפט לולאה עם postcondition (מתחיל במילה repeat), הביטוי השולט בביצוע חוזר של רצף של הצהרות כלול במשפט החזרה. צורת מחזור:

חזור על S עד B;

כאשר B הוא תנאי לוגי, אשר אמיתותו נבדקת (זהו תנאי לסיום הלולאה);

S - הצהרת גוף לולאה אחת או יותר.

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

הרצאה מס' 3. נהלים ותפקודים

1. הרעיון של אלגוריתם עזר

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

תת-שגרה היא אלגוריתם עזר שמשתמשים בו שוב ושוב באלגוריתם הראשי עם ערכים שונים של כמה כמויות נכנסות, הנקראים פרמטרים.

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

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

1) פרמטרים-משתנים;

2) פרמטרים קבועים;

3) פרמטרים-ערכים;

4) פרמטרי פרוצדורה ופרמטרים של פונקציות, כלומר פרמטרים מסוג פרוצדורלי;

5) פרמטרים משתנים ללא הקלדה.

הטקסטים של נהלים ופונקציות ממוקמים בחלק של תיאורי נהלים ופונקציות.

העברת שמות פרוצדורות ופונקציות כפרמטרים

בבעיות רבות, במיוחד במתמטיקה חישובית, יש צורך להעביר שמות של פרוצדורות ופונקציות כפרמטרים. לשם כך, TURBO PASCAL הציגה סוג נתונים חדש - פרוצדורלי או פונקציונלי, בהתאם למה שמתואר. (סוגי פרוצדורלים ופונקציות מתוארים בסעיף הצהרת הסוג.)

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

סוג

Proc = פרוצדורה;

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

2. נהלים בפסקל

כל תיאור פרוצדורה מכיל כותרת ואחריה בלוק תוכנית. הצורה הכללית של כותרת ההליך היא כדלקמן:

נוהל <name> [(<רשימת פרמטרים פורמליים>)];

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

3. פונקציות בפסקל

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

פונקציה <שם> [(<רשימת פרמטרים פורמליים>)]: <סוג החזר>;

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

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

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

4. העברת תיאורים וחיבור של תתי שגרות. הוֹרָאָה

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

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

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

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

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

דוגמה

1) {SE+} - חיקוי מעבד מתמטי;

2) {SF+} - יוצרים סוג מרוחק של הליך וקריאה לפונקציה;

3) {SN+} - השתמש במעבד שותף מתמטי;

4) {SR+} - בדוק אם הטווחים מחוץ לתחום.

מתגי קומפילציה מסוימים עשויים להכיל פרמטר, לדוגמה:

{$1 file name} - כלול את הקובץ בעל השם בטקסט של התוכנית הקומפילטית.

הרצאה מס' 4. תתי שגרות

1. פרמטרים של תוכנית משנה

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

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

1. קבוצת פרמטרים ללא מילת מפתח קודמת היא רשימה של פרמטרים של ערך.

2. קבוצת פרמטרים שלפניה מילת המפתח const ואחריה סוג היא רשימה של פרמטרים קבועים.

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

4. קבוצה של פרמטרים שלפניהם מילת המפתח var או const ולא אחריה סוג היא רשימה של פרמטרים של משתנים שלא הוקלדו.

2. סוגי פרמטרים של תת שגרה

פרמטרים של ערך

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

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

פרמטרים קבועים

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

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

פרמטרים משתנים

פרמטר משתנה משמש כאשר יש להעביר ערך מפרוצדורה או פונקציה לתוכנית הקוראת. הפרמטר הממשי המתאים בהצהרה של פרוצדורה או קריאת פונקציה חייב להיות הפניה למשתנה. כאשר הליך או פונקציה מופעלים, המשתנה-הפרמטר הפורמלי מוחלף במשתנה הממשי, כל שינוי בערך של משתנה-הפרמטר הפורמלי בא לידי ביטוי בפרמטר בפועל.

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

פרמטרים לא מוקלדים

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

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

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

משתנים פרוצדורליים

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

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

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

1) זה לא צריך להיות הליך או פונקציה סטנדרטית;

2) לא ניתן לקנן הליך או פונקציה כזו;

3) אסור שהליך כזה יהיה הליך מוטבע;

4) אסור שזה יהיה הליך הפרעה.

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

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

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

פרמטרים של סוג פרוצדורלי

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

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

הרצאה מס' 5. סוג נתוני מחרוזת

1. סוג מחרוזת בפסקל

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

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

2. נהלים ופונקציות למשתנים מסוג מחרוזת

1. עותק פונקציה(S: מחרוזת; אינדקס, ספירה: מספר שלם): מחרוזת;

מחזירה מחרוזת משנה של מחרוזת. S הוא ביטוי מסוג String.

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

2. הליך מחיקה (var S: מחרוזת; אינדקס, ספירה: מספר שלם);

מסיר מחרוזת משנה של תווים באורך Count מהמחרוזת S, החל ממיקום אינדקס. S הוא משתנה מסוג String. אינדקס וספירה הם ביטויים מסוג מספר שלם. אם אינדקס גדול מאורך S, לא יוסרו תווים.

3. Procedure Insert(מקור: String; var S: String; אינדקס: מספר שלם);

משרשרת תת-מחרוזת למחרוזת, מתחילה במיקום מוגדר. מקור הוא ביטוי מסוג String. S הוא משתנה מסוג String בכל אורך. אינדקס הוא ביטוי מסוג מספר שלם. Insert מוסיף מקור ל-S, מתחיל במיקום S[Index].

4. אורך הפונקציה (S: מחרוזת): מספר שלם;

מחזירה את מספר התווים המשמשים בפועל במחרוזת S. שימו לב שכאשר משתמשים במחרוזות עם סיומת Null, מספר התווים אינו שווה בהכרח למספר הבתים.

5. פונקציה Pos(Substr: String; S: String): מספר שלם;

מחפש תת-מחרוזת במחרוזת. Pos מחפש Substr בתוך S ומחזיר ערך שלם שהוא האינדקס של התו הראשון של Substr בתוך S. אם Substr לא נמצא, Pos מחזירה null.

3. הקלטות

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

תיאור רשומה בשפת פסקל מתבצע באמצעות מילת השירות RECORD ולאחריה תיאור מרכיבי הרשומה. תיאור הערך מסתיים במילת השירות END.

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

הקלד שורה = שיא

FIO: מחרוזת[20];

טל: מחרוזת[7];

הסוף;

var str: שורה;

תיאורי רשומות אפשריים גם ללא שימוש בשם הסוג, לדוגמה:

var str : שיא

FIO : String[20];

טל : מחרוזת[7];

הסוף;

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

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

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

4. סטים

המושג קבוצה בשפת פסקל מבוסס על המושג המתמטי של קבוצות: זהו אוסף מצומצם של אלמנטים שונים. סוג נתונים מסופר או מרווח משמש לבניית סוג סט קונקרטי. סוג האלמנטים המרכיבים קבוצה נקרא סוג הבסיס.

סוג מרובה מתואר באמצעות קבוצת מילות הפונקציה, לדוגמה:

סוג M = סט של B;

כאן M הוא סוג הרבים, B הוא סוג הבסיס.

ניתן לקבוע את השתייכותם של משתנים לסוג רבים ישירות בסעיף הצהרת משתנים.

קבועי סוג קבוצה נכתבים כרצף בסוגריים של אלמנטים או מרווחים מסוג בסיס, מופרדים בפסיקים. קבוע של הצורה [] פירושו תת-קבוצה ריקה.

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

פעולות הקצאה (:=), איחוד (+), חיתוך (*) וחיסור (-) ישימות על משתנים וקבועים מסוג קבוצה. התוצאה של פעולות אלו היא ערך מסוג רבים:

1) ['A','B'] + ['A','D'] ייתן ['A','B','D'];

2) ['א'] * ['א','ב','ג'] ייתן ['א'];

3) ['א','ב','ג'] - ['א','ב'] ייתן ['ג'].

פעולות ישימות לערכים מרובים: זהות (=), אי-זהות (<>), הכלולה ב-(<=), מכילה (>=). לתוצאה של פעולות אלה יש סוג בוליאני:

1) ['A','B'] = ['A','C'] ייתן FALSE;

2) ['א','ב'] <> ['א','ג'] יתן TRUE;

3) ['B'] <= ['B','C'] ייתן TRUE;

4) ['C','D'] >= ['A'] ייתן FALSE.

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

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

ערכים מסוג מרובה אינם יכולים להיות אלמנטים של רשימת קלט/פלט. בכל יישום ספציפי של המתרגם משפת פסקל, מספר האלמנטים מסוג הבסיס עליו בנוי הסט מוגבל.

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

להלן כמה נהלים לעבודה עם סטים.

1. Procedure Exclude(var S: Set of T; I:T);

מסיר את האלמנט I מהקבוצה S. S הוא משתנה מסוג "סט" ו-I הוא ביטוי של סוג התואם לסוג המקורי של S. Exclude(S, I) זהה ל-S : = S - [I] , אך מייצר קוד יעיל יותר.

2. Procedure Include(var S: Set of T; I:T);

מוסיף אלמנט I לקבוצה S. S הוא משתנה מסוג "סט" ו-I הוא ביטוי של טיפוס התואם לסוג S. המבנה Include(S, I) זהה ל-S : = S + [ I], אך מייצר קוד יעיל יותר.

הרצאה מס' 6. קבצים

1. קבצים. פעולות קובץ

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

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

בעבודה עם קבצים מבוצעות פעולות I/O. פעולת קלט פירושה העברת נתונים מהתקן חיצוני (מקובץ קלט) לזיכרון הראשי של מחשב, פעולת פלט היא העברת נתונים מהזיכרון הראשי להתקן חיצוני (לקובץ פלט). קבצים במכשירים חיצוניים מכונים לעתים קרובות קבצים פיזיים. שמותיהם נקבעים על ידי מערכת ההפעלה.

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

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

קבצי טקסט

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

var TF1, TF2: טקסט;

קבצי טקסט הם רצף של שורות, וקווים הם רצף של תווים. קווים הם באורך משתנה, כל שורה מסתיימת עם מסיים קו.

קבצי רכיבים

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

התיאור של ערכי סוג הקובץ הוא:

סוג M = File Of T;

כאשר M הוא שם סוג הקובץ;

T - סוג רכיב.

רכיבי הקבצים יכולים להיות כל הסוגים הסקלרים, ומסוגים מובנים - מערכים, סטים, רשומות. כמעט בכל ההטמעות הספציפיות של שפת פסקל, מבנה "קובץ הקבצים" אינו מותר.

כל הפעולות על קבצי רכיב מבוצעות באמצעות נהלים סטנדרטיים.

כתוב(f,X1,X2,...XK)

קבצים לא מודפסים

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

var f: קובץ;

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

1. Procedure Assign(var F; FileName: String);

הליך AssignFile ממפה שם קובץ חיצוני למשתנה קובץ.

F הוא משתנה קובץ מכל סוג קובץ, FileName הוא ביטוי מחרוזת, או ביטוי PChar אם מותר תחביר מורחב. כל הפעולות הנוספות עם F מבוצעות עם קובץ חיצוני.

לא ניתן להשתמש בהליך עם משתנה קובץ שכבר פתוח.

2. נוהל Close(var F);

ההליך שובר את הקישור בין משתנה הקובץ לקובץ הדיסק החיצוני וסוגר את הקובץ.

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

ההנחיה {SI+} מאפשרת לך לטפל בשגיאות במהלך הפעלת התוכנית באמצעות טיפול בחריגים. כשההנחיה {$1-} כבויה, עליך להשתמש ב-IOResult כדי לבדוק אם יש שגיאות קלט/פלט.

3.פונקציה Eof(var F): בוליאנית;

{קבצים שהוקלדו או לא הוקלדו}

פונקציה Eof[(var F: Text)]: בוליאנית;

{קבצי טקסט}

בודק אם מיקום הקובץ הנוכחי הוא סוף הקובץ או לא.

Eof(F) מחזירה True אם מיקום הקובץ הנוכחי הוא אחרי התו האחרון של הקובץ, או אם הקובץ ריק; אחרת Eof(F) מחזירה False.

ההנחיה {SI+} מאפשרת לך לטפל בשגיאות במהלך הפעלת התוכנית באמצעות טיפול בחריגים. כשההנחיה {SI-} כבויה, עליך להשתמש ב-IOResult כדי לבדוק אם יש שגיאות קלט/פלט.

4. Procedure Erase(varF);

מוחק את הקובץ החיצוני המשויך ל-F.

F הוא משתנה קובץ מכל סוג קובץ.

יש לסגור את הקובץ לפני שקוראים להליך המחיקה.

ההנחיה {SI+} מאפשרת לך לטפל בשגיאות במהלך הפעלת התוכנית באמצעות טיפול בחריגים. כשההנחיה {SI-} כבויה, עליך להשתמש ב-IOResult כדי לבדוק אם יש שגיאות קלט/פלט.

5. פונקציה FileSize(var F): מספר שלם;

מחזירה את הגודל בבתים של קובץ F עם זאת, אם F הוא קובץ מוקלד, FileSize יחזיר את מספר הרשומות בקובץ. הקובץ חייב להיות פתוח לפני השימוש בפונקציה FileSize. אם הקובץ ריק, FileSize(F) מחזיר אפס. F הוא משתנה מכל סוג קובץ.

6.Function FilePos(var F): LongInt;

מחזירה את המיקום הנוכחי של קובץ בתוך קובץ.

לפני השימוש בפונקציית FilePos, הקובץ חייב להיות פתוח. הפונקציה FilePos אינה בשימוש עם קבצי טקסט. F הוא משתנה מכל סוג קובץ, למעט סוג הטקסט.

7. איפוס הליך (var F [: File; RecSize: Word]);

פותח קובץ קיים.

F הוא משתנה מכל סוג קובץ המשויך לקובץ חיצוני באמצעות AssignFile. RecSize הוא ביטוי אופציונלי המשמש אם F הוא קובץ לא מודפס. אם F הוא קובץ ללא הקלדה, RecSize קובע את גודל הרשומה המשמש בעת העברת נתונים. אם RecSize מושמט, גודל הרשומה המוגדר כברירת מחדל הוא 128 בתים.

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

8. הליך שכתוב (var F: File [; גודל מחדש: Word]);

יוצר ופותח קובץ חדש.

F הוא משתנה מכל סוג קובץ המשויך לקובץ חיצוני באמצעות AssignFile. RecSize הוא ביטוי אופציונלי המשמש אם F הוא קובץ לא מודפס. אם F הוא קובץ ללא הקלדה, RecSize קובע את גודל הרשומה המשמש בעת העברת נתונים. אם RecSize מושמט, גודל הרשומה המוגדר כברירת מחדל הוא 128 בתים.

הליך השכתוב יוצר קובץ חיצוני חדש עם השם המשויך ל-F. אם כבר קיים קובץ חיצוני באותו שם, הוא נמחק ונוצר קובץ ריק חדש.

9. Procedure Seek(var F; N: LongInt);

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

המיקום הנוכחי של קובץ F מועבר למספר N. המספר של הרכיב הראשון של הקובץ הוא 0.

ההוראה Seek(F, FileSize(F)) מזיזה את מיקום הקובץ הנוכחי לסוף הקובץ.

10. נוהל Append(var F: Text);

פותח קובץ טקסט קיים כדי להוסיף מידע לסוף הקובץ (הוסף).

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

11.פונקציה Eoln[(var F: Text)]: בוליאני;

בודק אם מיקום הקובץ הנוכחי הוא סוף שורה בקובץ טקסט.

Eoln(F) מחזירה True אם מיקום הקובץ הנוכחי נמצא בסוף שורה או קובץ; אחרת Eoln(F) מחזירה False.

12. הליך קריאה (F, V1 [, V2,..., Vn]);

{קבצים שהוקלדו ולא הוקלדו}

Procedure Read([var F: Text;] V1 [, V2,..., Vn]);

{קבצי טקסט}

עבור קבצים מוקלדים, ההליך קורא את רכיב הקובץ למשתנה. בכל קריאה, המיקום הנוכחי בקובץ מתקדם לרכיב הבא.

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

עם משתני מחרוזת, Read קורא את כל התווים עד (אך לא כולל) סמן סוף השורה הבא, או עד Eof(F) מוערך ל-True. מחרוזת התווים המתקבלת מוקצית למשתנה.

במקרה של משתנה מסוג שלם או ממשי, ההליך ממתין לרצף של תווים היוצרים מספר לפי כללי תחביר פסקל. הקריאה נעצרת כאשר נתקלים ברווח הראשון, בטאב או בסוף השורה, או אם Eof(F) מוערך כ-True. אם המחרוזת המספרית אינה תואמת לפורמט הצפוי, מתרחשת שגיאת קלט/פלט.

13. נוהל Readln([var F: Text;] V1 [, V2..., Vn]);

זוהי הרחבה של נוהל קריאה ומוגדרת עבור קבצי טקסט. קורא מחרוזת תווים בקובץ, כולל סמן סוף השורה, ומתקדם לתחילת השורה הבאה. קריאה לפונקציה Readln(F) ללא פרמטרים מעבירה את מיקום הקובץ הנוכחי לתחילת השורה הבאה, אם יש כזו, אחרת היא קופצת לסוף הקובץ.

14. פונקציה SeekEof[(var F: Text)]: Boolean;

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

15. פונקציה SeekEoln[(var F: Text)]: Boolean;

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

16. הליך כתיבה([var F: Text;] P1 [, P2,..., Pn]);

{קבצי טקסט}

כותב ערך אחד או יותר לקובץ טקסט.

כל פרמטר כניסה חייב להיות מסוג Char, אחד מסוגי המספרים השלמים (Byte, ShortInt, Word, Longint, Cardinal), אחד מסוגי הנקודה הצפה (Single, Real, Double, Extended, Currency), אחד מסוגי המחרוזות ( PChar, AisiString, ShortString), או אחד מהסוגים הבוליאניים (Boolean, Bool).

הליך כתיבה (F, V1,..., Vn);

{הקלד קבצים}

כותב משתנה לרכיב קובץ. משתנים VI...., Vn חייבים להיות מאותו סוג של רכיבי הקובץ. בכל פעם שנכתב משתנה, המיקום הנוכחי בקובץ מועבר לאלמנט הבא.

17. הליך Writeln([var F: Text;] [P1, P2,..., Pn]);

{קבצי טקסט}

מבצע פעולת כתיבה ולאחר מכן מציב סמן של סוף שורה בקובץ.

קריאת Writeln(F) ללא פרמטרים כותבת סמן של סוף שורה לקובץ. הקובץ חייב להיות פתוח לפלט.

2. מודולים. סוגי מודולים

מודול (1Ж1Т) בפסקל הוא ספרייה שתוכננה במיוחד של תתי שגרות. לא ניתן להפעיל מודול, בניגוד לתוכנית, לביצוע בעצמו, הוא יכול להשתתף רק בבניית תוכניות ומודולים אחרים. מודולים מאפשרים לך ליצור ספריות אישיות של נהלים ופונקציות ולבנות תוכניות כמעט בכל גודל.

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

ניתן לחלק את כל רכיבי התוכנית של המודול לשני חלקים:

1) רכיבי תוכנית המיועדים לשימוש על ידי תוכניות או מודולים אחרים, רכיבים כאלה נקראים גלויים מחוץ למודול;

2) רכיבי תוכנה הנחוצים רק לתפעול המודול עצמו, הם נקראים בלתי נראים (או מוסתרים).

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

באופן כללי, למודול יש את המבנה הבא:

unit <שם מודול>; {כותרת מודול}

ממשק

{תיאור של רכיבי תוכנית גלויים של המודול}

הפעלה

{תיאור של רכיבי התכנות הנסתרים של המודול}

להתחיל

{הצהרות אתחול של רכיב מודול}

הסוף.

במקרה מסוים, ייתכן שהמודול לא יכיל חלק יישום וחלק אתחול, ואז מבנה המודול יהיה כדלקמן:

unit <שם מודול>; {כותרת מודול}

ממשק

{תיאור של רכיבי תוכנית גלויים של המודול}

הפעלה

הסוף.

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

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

יש להדר את קוד המקור של המודול באמצעות הוראת Make של תת-תפריט Compile ולכתוב לדיסק. התוצאה של קומפילציה של מודול היא קובץ עם סיומת. TPU (יחידת טורבו פסקל). שם הבסיס של המודול נלקח מהכותרת של המודול.

כדי לחבר מודול לתוכנית, עליך לציין את שמו בסעיף תיאור המודול, לדוגמה:

משתמש ב- Crt, Graph;

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

שימוש רקורסיבי במודולים אסור.

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

בואו נפרט את סוגי המודולים.

1. מודול מערכת.

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

מודול SYSTEM מכיל את כל השגרות והפונקציות הסטנדרטיות והמובנות של Pascal. כל תת שגרת פסקל שאינה חלק מ-Pascal הסטנדרטי ואינה נמצאת באף מודול אחר כלולה במודול המערכת. מודול זה נמצא בשימוש אוטומטי בכל התוכניות ואין צורך לציין אותו בהצהרת uses.

2. מודול DOS.

מודול ה-Dos מיישם מספר שגרות ופונקציות של Pascal המקבילות לקריאות ה-DOS הנפוצות ביותר, כגון GetTime, SetTime, DiskSize וכן הלאה.

3. מודול CRT.

מודול ה-CRT מיישם מספר תוכניות חזקות המספקות שליטה מלאה על תכונות המחשב כגון בקרת מצב מסך, קודי מקלדת מורחבים, צבעים, חלונות וצלילים. ניתן להשתמש במודול ה-CRT רק בתוכניות הפועלות במחשבים אישיים IBM PC, PC AT, PS/2 מבית IBM והן תואמות באופן מלא איתן.

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

4. מודול GRAPH.

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

5. מודול OVERLAY.

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

הרצאה מס' 7. זיכרון דינמי

1. סוג נתוני הפניה. זיכרון דינמי. משתנים דינמיים

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

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

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

המילה השמורה אפס מציינת קבוע עם ערך מצביע שאינו מצביע על שום דבר.

הבה ניתן דוגמה לתיאור של משתנים דינמיים.

var p1, p2 : ^real;

p3, p4 : ^מספר שלם;

2. עבודה עם זיכרון דינמי. מצביעים לא מודפסים

נהלים ופונקציות של זיכרון דינמי

1. נוהל חדש (var p: Pointer).

מקצה מקום באזור הזיכרון הדינמי כדי להכיל את המשתנה הדינמי pЛ, ומקצה את כתובתו למצביע p.

2. נוהל Dispose (varp: Pointer).

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

3. הליך GetMem (varp: Pointer; גודל: Word).

מקצה קטע זיכרון ב-heap-area, מקצה את הכתובת של ההתחלה שלו למצביע p, גודל הקטע בבתים מוגדר על ידי פרמטר הגודל.

4. נוהל FreeMem (var p: Pointer; גודל: Word).

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

5. סימן נוהל (var p: Pointer)

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

6. שחרור נוהל (var p: Pointer)

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

7. פונקציית MaxAvaikLongint

מחזירה את האורך, בבתים, של הערימה הפנויה הארוכה ביותר.

8. פונקציית MemAvaikLongint

מחזירה את הכמות הכוללת של זיכרון דינמי פנוי בבתים.

9. פונקציית עוזר SizeOf(X):Word

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

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

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

הרצאה מס' 8. מבני נתונים מופשטים

1. מבני נתונים מופשטים

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

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

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

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

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

1) הוספת אלמנט לרשימה;

2) הסרת אלמנט מהרשימה עם מפתח נתון;

3) חפש אלמנט עם ערך נתון של שדה המפתח;

4) מיון מרכיבי הרשימה;

5) חלוקת הרשימה לשתי רשימות או יותר;

6) שילוב של שתי רשימות או יותר לאחת;

7) פעולות אחרות.

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

2. ערימות

מחסנית היא מבנה נתונים דינמי, תוספת של רכיב אליו והסרה של רכיב ממנו עשויים מקצה אחד, הנקרא החלק העליון של הערימה. המחסנית עובדת על העיקרון של LIFO (Last-In, First-Out) - "Last in, first out".

בדרך כלל מבוצעות שלוש פעולות בערימות:

1) היווצרות ראשונית של הערימה (רשומה של הרכיב הראשון);

2) הוספת רכיב לערימה;

3) בחירת הרכיב (מחיקה).

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

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

תוכנית STACK;

משתמש ב- Crt;

סוג

Alpha = String[10];

PComp = ^Comp;

Comp = שיא

SD: אלפא

pNext: PComp

הסוף;

היה

pTop:PComp;

sc: אלפא;

Create ProcedureStack(var pTop: PComp; var sC: Alfa);

להתחיל

חדש(pTop);

pTop^.pNext := NIL;

pTop^.sD := sC;

הסוף;

הוסף ProcedureComp(var pTop : PComp; var sC : Alfa);

var pAux : PComp;

להתחיל

NEW(pAux);

pAux^.pNext := pTop;

pTop := pAux;

pTop^.sD := sC;

הסוף;

נוהל DelComp(var pTop : PComp; var sC : ALFA);

להתחיל

sC := pTop^.sD;

pTop := pTop^.pNext;

הסוף;

להתחיל

Clrscr;

writeln(' ENTER A STRING ');

readln(sc);

CreateStack(pTop, sc);

לחזור על

writeln(' ENTER A STRING ');

readln(sc);

AddComp(pTop, sc);

עד sC = 'END';

writeln('******** OUTPUT ******');

לחזור על

DelComp(pTop, sc);

writeln(sC);

עד pTop = NIL;

הסוף.

3. תורים

תור הוא מבנה נתונים דינמי שבו רכיב נוסף בקצה אחד ומאוחזר בקצה השני. התור עובד על העיקרון של FIFO (פירסט-in, First-Out) - "ראשון נכנס, ראשון".

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

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

ProgramQUEUE;

משתמש ב- Crt;

סוג

Alpha = String[10];

PComp = ^Comp;

Comp = שיא

SD: אלפא

pNext : PComp;

הסוף;

היה

pBegin, pEnd : PComp;

sc: אלפא;

Create ProcedureQueue(var pBegin,pEnd:PComp; var sC:Alfa);

להתחיל

חדש(pBegin);

pBegin^.pNext := NIL;

pBegin^.sD := sC;

pEnd := pBegin;

הסוף;

הליך הוסף ProcedureQueue(var pEnd : PComp; var sC : Alfa);

var pAux : PComp;

להתחיל

חדש(pAux);

pAux^.pNext := NIL;

pEnd^.pNext := pAux;

pEnd := pAux;

pEnd^.sD := sC;

הסוף;

נוהל DelQueue(var pBegin: PComp; var sC: Alfa);

להתחיל

sC := pBegin^.sD;

pBegin := pBegin^.pNext;

הסוף;

להתחיל

Clrscr;

writeln(' ENTER A STRING ');

readln(sc);

CreateQueue(pBegin, pEnd, sc);

לחזור על

writeln(' ENTER A STRING ');

readln(sc);

AddQueue(pEnd, sc);

עד sC = 'END';

writeln(' ***** תוצאות תצוגה *****');

לחזור על

DelQueue(pBegin, sc);

writeln(sC);

עד pBegin = NIL;

הסוף.

הרצאה מס' 9. מבני נתונים דמויי עץ

1. מבני נתונים עצים

מבנה נתונים דמוי עץ הוא קבוצה סופית של אלמנטים-צמתים שביניהם יש יחסים - הקשר בין המקור למיוצר.

אם נשתמש בהגדרה הרקורסיבית שהוצעה על ידי N. Wirth, אזי מבנה נתוני עץ עם סוג בסיס t הוא או מבנה ריק או צומת מסוג t, שאיתו קבוצה סופית של מבני עץ עם סוג בסיס t, הנקראים תת-עצים, היא קשור ל.

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

אם הצומת y ממוקם ישירות מתחת לצומת x, אזי הצומת y נקרא הצאצא המיידי של הצומת x, ו-x הוא האב הקדמון המיידי של הצומת y, כלומר, אם הצומת x נמצא ברמה ה-i, אז הצומת y הוא בהתאם. ממוקם ב (i + 1) - הרמה.

הרמה המקסימלית של צומת עץ נקראת גובה או עומק העץ. לאב קדמון אין רק צומת אחד של העץ - השורש שלו.

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

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

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

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

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

עץ שדרגתו גדולה משניים נקרא הסתעפות חזקה.

2. פעולות על עצים

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

I. בניית עצים

אנו מציגים אלגוריתם לבניית עץ מסודר.

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

2. כדי להוסיף צומת לעץ שכבר קיים, אתה יכול להשתמש באלגוריתם שלמעלה.

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

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

II. מציאת צומת עם ערך שדה מפתח נתון

בעת ביצוע פעולה זו, יש צורך לחצות את העץ. יש צורך לקחת בחשבון את הצורות השונות של כתיבת עץ: קידומת, infix ו-postfix.

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

TYPE TreeLink = ^Tree;

עץ = שיא;

Inf : <datatype>;

שמאל, ימין: TreeLink;

סוף.

3. דוגמאות לביצוע פעולות

1. בנה עץ של n צמתים בגובה מינימלי, או עץ מאוזן לחלוטין (מספר הצמתים של תת העצים השמאלי והימני של עץ כזה חייב להיות שונה בלא יותר מאחד).

אלגוריתם בנייה רקורסיבית:

1) הצומת הראשון נלקח כשורש העץ.

2) תת העץ השמאלי של צמתים nl בנוי באותו אופן.

3) תת העץ הימני של צמתים nr בנוי באותו אופן;

nr = n - nl - 1. כשדות מידע, ניקח את מספרי הצומת שהוזנו מהמקלדת. הפונקציה הרקורסיבית המיישמת בנייה זו תיראה כך:

פונקציה Tree(n: Byte): TreeLink;

Var t : TreeLink; nl,nr,x : Byte;

להתחיל

אם n = 0 אז Tree := אפס

אחר

להתחיל

nl := n div 2;

nr = n - nl - 1;

writeln('הזן מספר קודקוד ');

readln(x);

new(t);

t^.inf := x;

t^.left := Tree(nl);

t^.right := Tree(nr);

עץ := t;

סוף;

{עֵץ}

סוף.

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

הליך חיפוש (x : Byte; var t : TreeLink);

להתחיל

אם t = אפס אז

להתחיל

חדש(ט);

t^inf := x;

t^.left := אפס;

t^.right := אפס;

סוֹף

אחרת אם x < t^.inf אז

חפש (x, t^.left)

אחרת אם x > t^.inf אז

חפש (x, t^.right)

אחר

להתחיל

{process found element}

...

סוף;

סוף.

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

3.1. הליך הזמנה מראש (t : TreeLink);

להתחיל

אם t <> אפס אז

להתחיל

WriteIn(t^.inf);

Preorder(t^.left);

Preorder(t^.right);

סוף;

סוף;

3.2. הליך Inorder(t : TreeLink);

להתחיל

אם t <> אפס אז

להתחיל

Inorder(t^.left);

WriteIn(t^.inf);

Inorder(t^.right);

סוף;

סוף.

3.3. הליך Postorder(t : TreeLink);

להתחיל

אם t <> אפס אז

להתחיל

postorder(t^.left);

postorder(t^.right);

WriteIn(t^.inf);

סוף;

סוף.

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

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

הליך Delete1(x : Byte; var t : TreeLink);

Var p : TreeLink;

הליך Delete2(var q : TreeLink);

להתחיל

אם q^.right <> nil אז Delete2(q^.right)

אחר

להתחיל

p^.inf := q^.inf;

p := q;

q := q^.left;

סוף;

סוף;

להתחיל

אם t = אפס אז

Writeln('לא נמצא אלמנט')

אחרת אם x < t^.inf אז

מחק1(x, t^.left)

אחרת אם x > t^.inf אז

מחק1(x, t^.right)

אחר

להתחיל

P := t;

אם p^.שמאל = אפס אז

t := p^.right

אחר

אם p^.right = אפס אז

t := p^.שמאל

אחר

Delete2(p^.left);

סוף;

סוף.

הרצאה מס' 10. סופר

1. הרעיון של גרף. דרכים לייצוג גרף

גרף הוא זוג G = (V,E), כאשר V הוא קבוצה של עצמים בעלי אופי שרירותי, הנקראים קודקודים, ו-E היא משפחה של זוגות ei = (vil, vi2), vijOV, הנקראים קצוות. במקרה הכללי, קבוצת V ו/או משפחת E עשויים להכיל מספר אינסופי של אלמנטים, אך נשקול רק גרפים סופיים, כלומר גרפים שעבורם גם V וגם E הם סופיים. אם סדר האלמנטים הכלולים ב-ei משנה, אז הגרף נקרא מכוון, מקוצר - דיגרף, אחרת - בלתי מכוון. הקצוות של דיגרף נקראים קשתות. בהמשך, אנו מניחים שהמונח "גרף", בשימוש ללא מפרט (מכוון או בלתי מכוון), מציין גרף לא מכוון.

אם e = , אז הקודקודים v ו-u נקראים קצוות הקצה. כאן אנו אומרים שהקצה e צמוד (אירוע) לכל אחד מהקודקודים v ו-u. קודקודים v ו ו נקראים גם סמוכים (אירוע). במקרה הכללי, קצוות הצורה e = ; קצוות כאלה נקראים לולאות.

מידת הקודקוד בגרף היא מספר הקצוות הנכנסים לאותו קודקוד, כאשר לולאות נספרות פעמיים. מכיוון שכל קצה נופל לשני קודקודים, סכום המעלות של כל הקודקודים בגרף שווה לכפול ממספר הקצוות: Sum(deg(vi), i=1...|V|) = 2 * | ה|.

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

נתיב בגרף (או מסלול בדיגרף) הוא רצף מתחלף של קודקודים וקצוות (או קשתות בדיגרף) בצורה v0, (v0,v1), v1..., (vn - 1,vn ), vn. המספר n נקרא אורך הנתיב. נתיב ללא קצוות חוזרים נקרא שרשרת נתיב ללא קודקודים חוזרים נקרא שרשרת פשוטה. ניתן לסגור את הנתיב (v0 = vn). שביל סגור ללא קצוות חוזרים נקרא מחזור (או קו מתאר בדיגרף); ללא קודקודים חוזרים (למעט הראשון והאחרון) - לולאה פשוטה.

גרף נקרא מחובר אם יש נתיב בין כל שני קודקודים שלו, ומנותק אחרת. גרף מנותק מורכב ממספר רכיבים מחוברים (תתי גרפים מחוברים).

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

1. מטריצת שכיחות.

זוהי מטריצה ​​מלבנית של ממד nx n, כאשר n הוא מספר הקודקודים, am הוא מספר הקצוות. הערכים של רכיבי המטריצה ​​נקבעים באופן הבא: אם הקצה xi והקודקוד vj תקפים, אז הערך של אלמנט המטריצה ​​המקביל שווה לאחד, אחרת הערך הוא אפס. עבור גרפים מכוונים, מטריצת השכיחות בנויה על פי העיקרון הבא: הערך של האלמנט שווה ל- 1 אם קצה xi מגיע מקודקוד vj, שווה ל-1 אם קצה xi נכנס לקודקוד vj, ושווה ל-XNUMX אחרת .

2. מטריצת סמיכות.

זוהי מטריצה ​​מרובעת של הממד nxn, כאשר n הוא מספר הקודקודים. אם הקודקודים vi ו-vj סמוכים, כלומר אם יש קצה המחבר ביניהם, אז האלמנט המטריצה ​​המתאים שווה לאחד, אחרת הוא שווה לאפס. הכללים לבניית מטריצה ​​זו עבור גרפים מכוונים ובלתי מכוונים אינם שונים. מטריצת הסמיכות קומפקטית יותר ממטריצת השכיחות. יש לציין שגם המטריצה ​​הזו דלילה מאוד, אבל במקרה של גרף לא מכוון היא סימטרית ביחס לאלכסון הראשי, כך שניתן לאחסן לא את כל המטריצה ​​אלא רק חצי ממנה (מטריקס משולש ).

3. רשימת סמיכות (תקריות).

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

רשימת סמיכות יעילה יותר ממטריצת סמיכות מכיוון שהיא מבטלת את האחסון של אלמנטים null.

4. רשימת רשימות.

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

2. ייצוג גרף לפי רשימת שכיחות. אלגוריתם חציית עומק גרף

כדי ליישם גרף כרשימת שכיחות, אתה יכול להשתמש בסוג הבא:

TypeList = ^S;

S=שיא;

inf: Byte;

הבא: רשימה;

הסוף;

לאחר מכן, הגרף מוגדר כך:

Var Gr : מערך[1..n] של רשימה;

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

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

בפסקל, הליך המעבר לעומק ראשון ייראה כך:

נוהל Obhod(gr : Graph; k : Byte);

Var g : גרף; l : רשימה;

להתחיל

nov[k] := false;

g := gr;

בעוד g^.inf <> k do

g := g^.next;

l := g^.smeg;

בעוד אני <> אפס כן מתחילים

אם nov[l^.inf] אז Obhod(gr, l^.inf);

l := l^.הבא;

סוף;

סוף;

שים לב

בהליך זה, בעת תיאור סוג הגרף, התכוונו לתיאור של גרף באמצעות רשימה של רשימות. מערך nov[i] הוא מערך מיוחד שהאלמנט ה-i שלו הוא True אם הקודקוד ה-i אינו מבקר, ו- False אחרת.

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

3. ייצוג גרף לפי רשימת רשימות. אלגוריתם מעבר גרף רוחב

ניתן להגדיר גרף באמצעות רשימה של רשימות באופן הבא:

TypeList = ^Tlist;

tlist=record

inf: Byte;

הבא: רשימה;

הסוף;

גרף = ^TGpaph;

TGpaph = שיא

inf: Byte;

smeg : רשימה;

הבא : גרף;

הסוף;

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

הנה הליך למעבר גרף ברוחב בפסאודוקוד:

נוהל Obhod2(v);

{values ​​​​spisok, נובמבר - גלובלי}

להתחיל

תור = O;

תור <= v;

nov[v] = שקר;

בעוד תור <> O לעשות

להתחיל

p <= תור;

עבור u in spisok(p) לעשות

אם חדש[u] אז

להתחיל

nov[u] := שקר;

תור <= u;

סוף;

סוף;

סוף;

הרצאה מס' 11. סוג נתוני אובייקט

1. סוג אובייקט בפסקל. מושג החפץ, התיאור והשימוש בו

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

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

1) עיצוב מלמעלה למטה;

2) תכנות מודולרי;

3) קידוד מבני.

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

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

1) אנקפסולציה. שילוב של רשומות עם נהלים ופונקציות המבצעות מניפולציות בשדות של רשומות אלה יוצר סוג נתונים חדש - אובייקט;

2) ירושה. הגדרת אובייקט ושימוש נוסף בו לבניית היררכיה של אובייקטים צאצאים עם היכולת של כל אובייקט צאצא הקשור בהיררכיה לגשת לקוד ולנתונים של כל אובייקטי האב;

3) פולימורפיזם. מתן שם יחיד לפעולה, אשר לאחר מכן משותף למעלה ולמטה בהיררכיית האובייקטים, כאשר כל אובייקט בהיררכיה מבצע את הפעולה באופן המתאים לו.

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

סוג אובייקט יכול לרשת רכיבים מסוג אובייקט אחר. אם סוג T2 יורש מסוג T1, אז סוג T2 הוא ילד מסוג T1, וסוג T1 עצמו הוא אב מסוג T2. הירושה היא טרנזיטיבית, כלומר אם TK יורש מ-T2, ו-T2 יורש מ-T1, אז TK יורש מ-T1. היקף (דומיין) של סוג אובייקט מורכב מעצמו ומכל צאצאיו.

קוד המקור הבא הוא דוגמה להצהרת סוג אובייקט, type

סוג

נקודה = אובייקט

X, Y: מספר שלם;

הסוף;

Rect = חפץ

A, B: TPoint;

פרוצדורה Init(XA, YA, XB, YB: מספר שלם);

הליך Copy(var R: TRectangle);

פרוצדורה Move(DX, DY: מספר שלם);

הליך Grow(DX, DY: מספר שלם);

procedure Intersect(var R: TRectangle);

procedure Union(var R: TRectangle);

function Contains(P: Point): Boolean;

הסוף;

StringPtr = ^String;

FieldPtr = ^TFeld;

TField = אובייקט

X, Y, Len: מספר שלם;

שם: StringPtr;

constructor Copy(var F: TField);

בנאי Init(FX, FY, FLen: שלם; FName: String);

ההרס בוצע; וירטואלי;

הליך תצוגה; וירטואלי;

הליך עריכה; וירטואלי;

function GetStr: מחרוזת; וירטואלי;

function PutStr(S: String): Boolean; וירטואלי;

הסוף;

StrFieldPtr = ^TSrField;

StrField = object(TFeld)

ערך: PString;

בנאי Init(FX, FY, FLen: שלם; FName: String);

ההרס בוצע; וירטואלי;

function GetStr: מחרוזת; וירטואלי;

function PutStr(S: String): Boolean;

וירטואלי;

פונקציה Get:string;

הליך Put(S: String);

הסוף;

NumFieldPtr = ^TNumField;

TNumField = אובייקט(TFeld)

פְּרָטִי

ערך, מינימום, מקסימום: Longint;

ציבורי

בנאי Init(FX, FY, FLen: מספר שלם; FName: String;

FMin, FMax: Longint);

function GetStr: מחרוזת; וירטואלי;

function PutStr(S: String): Boolean; וירטואלי;

פונקציה Get: Longint;

function Put(N: Longint);

הסוף;

ZipFieldPtr = ^TZipField;

ZipField = object(TNumField)

function GetStr: מחרוזת; וירטואלי;

function PutStr(S: String): Boolean;

וירטואלי;

הסוף.

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

לסוג רכיב מסוג קובץ לא יכול להיות סוג אובייקט או כל סוג מבנה המכיל רכיבים מסוג אובייקט.

2. ירושה

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

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

3. יצירת אובייקטים

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

היה

F: TField;

Z: TZipField;

FP:PFeld;

ZP: PZipField;

בהתחשב בהצהרות משתנות אלו, F הוא מופע של TField ו-Z הוא מופע של TZipField. באופן דומה, לאחר החלת New על FP ו-ZP, FP יצביע על מופע TField, ו-ZP יצביע על מופע TZipField.

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

להלן דוגמה:

היה

S: StrField;

egin

S.Init(1, 1, 25, 'שם פרטי');

S.Put('ולדימיר');

S.תצוגה;

...

S בוצע;

הסוף.

אם לא נקראה S.Init, קריאת S.Display תגרום לכשל של דוגמה זו.

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

אם מופע האובייקט אינו מאותחל ובדיקת טווחים מופעלת (על פי ההנחיה {SR+}), אז הקריאה הראשונה למתודה הוירטואלית של מופע האובייקט נותנת שגיאת זמן ריצה. אם בדיקת הטווח מושבתת (על פי ההנחיה {SR-}), אז הקריאה הראשונה לשיטה וירטואלית של אובייקט לא מאותחל עלולה להוביל להתנהגות בלתי צפויה.

כלל האתחול החובה חל גם על מופעים שהם רכיבים של סוגי struct. לדוגמה:

היה

הערה: מערך [1..5] של TStrField;

אני: מספר שלם

להתחיל

עבור I := 1 עד 5 לעשות

הערה [I].Init (1, I + 10, 40, 'first_name');

.

.

.

עבור I := 1 עד 5 do Comment [I].Done;

הסוף;

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

היה

SP: StrFieldPtr;

להתחיל

New(SP, Init(1, 1, 25, 'first_name');

SP^.Put('Vladimir');

SP^.תצוגה;

.

.

.

השלך (SP, Done);

הסוף.

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

לדוגמה, ניתן להקצות מצביע מסוג ZipFieldPtr למצביעים מסוג PZipField, PNumField ו-PFeld, ובזמן ריצה, מצביע מסוג PField יכול להיות אפס או להצביע על מופע של TField, TNumField או TZipField, או כל מופע של סוג ילד של TField. .

כללי תאימות מצביעי הקצאה אלה חלים גם על פרמטרים של סוג אובייקט. לדוגמה, ניתן להעביר את שיטת TField.Cop למופעים של TField, TStrField, TNumField, TZipField, או כל סוג אחר של צאצא של TField.

4. רכיבים והיקף

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

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

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

הרצאה מס' 12. שיטות

1. שיטות

הצהרת שיטה בתוך סוג אובייקט תואמת הצהרת שיטה קדימה (Forward). לפיכך, איפשהו לאחר הצהרת סוג אובייקט, אך באותו היקף כמו היקף הצהרת סוג אובייקט, יש ליישם שיטה על ידי הגדרת ההצהרה שלה.

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

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

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

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

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

עם עשייה עצמית

להתחיל

...

הסוף;

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

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

שיטות וירטואליות

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

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

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

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

שיטות דינמיות

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

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

הליך FileOpen(var Msg: TMessage); וירטואלי 100;

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

2. קונסטרוקטים והורסים

בנאים והרסים הם צורות מיוחדות של שיטות. בשימוש בקשר עם התחביר המורחב של ההליכים הסטנדרטיים New ו-Dispose, לבנאים והרסנים יש את היכולת למקם ולהסיר אובייקטים דינמיים. בנוסף, לבנאים יש את היכולת לבצע את האתחול הנדרש של אובייקטים המכילים שיטות וירטואליות. כמו כל שיטות אחרות, בנאים והרסנים יכולים לעבור בתורשה, ואובייקטים יכולים להכיל כל מספר של בנאים והרסים.

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

הנה כמה דוגמאות לבנאים:

בנאי Field.Copy(var F: Field);

להתחיל

עצמי := F;

הסוף;

בנאי Field.Init(FX, FY, FLen: מספר שלם; FName: מחרוזת);

להתחיל

X := FX;

Y := FY;

GetMem(Name, Length(FName) + 1);

שם^ := FName;

הסוף;

בנאי TStrField.Init(FX, FY, FLen: מספר שלם; FName: מחרוזת);

להתחיל

בירושה Init(FX, FY, FLen, FName);

Field.Init(FX, FY, FLen, FName);

GetMem(Value, Len);

ערך^ := '';

הסוף;

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

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

שים לב

הורס יכול להיות וירטואלי, ולעתים קרובות הוא. לעתים רחוקות יש להרס פרמטרים.

הנה כמה דוגמאות להרסים:

ההורס שדה בוצע;

להתחיל

FreeMem(שם, אורך(שם^) + 1);

הסוף;

משמיד StrField.Done;

להתחיל

FreeMem(Value, Len);

השדה נעשה;

הסוף;

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

3. הורסים

Borland Pascal מספקת סוג מיוחד של שיטה הנקראת אוסף אשפה (או משמיד) לניקוי ומחיקה של אובייקט שהוקצה באופן דינמי. המשמיד משלב את השלב של מחיקת אובייקט עם כל פעולה או משימות אחרות הנדרשות עבור סוג זה של אובייקט. ניתן להגדיר משמידים מרובים עבור סוג אובייקט בודד.

ה-Destructor מוגדר יחד עם כל שאר שיטות האובייקט בהגדרת הסוג של האובייקט:

סוּג

עובד עבודה = חפץ

שם: מחרוזת[25];

כותרת: מחרוזת[25];

תעריף: אמיתי;

הבנאי Init(AName, ATitle: String; ARate: Real);

ההרס בוצע; וירטואלי;

function GetName: מחרוזת;

פונקציה GetTitle: מחרוזת;

פונקציה GetRate: Rate; וירטואלי;

פונקציה GetPayAmount: אמיתי; וירטואלי;

הסוף;

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

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

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

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

אובייקטים פולימורפיים הם אותם אובייקטים שהוקצו לסוג אב עקב כללי תאימות הסוג המורחבים של Borland Pascal. מופע של אובייקט מסוג THourly המוקצה למשתנה מסוג TEmployee הוא דוגמה לאובייקט פולימורפי. ניתן להחיל כללים אלה גם על אובייקטים; ניתן להקצות מצביע ל-THourly באופן חופשי למצביע ל-TEmployee, והאובייקט שאליו מצביע המצביע יהיה שוב אובייקט פולימורפי. המונח "פולימורפי" מתאים מכיוון שקוד שמעבד אובייקט "לא יודע" בדיוק בזמן הקומפילציה איזה סוג אובייקט הוא יצטרך בסופו של דבר לעבד. הדבר היחיד שהוא יודע הוא שאובייקט זה שייך להיררכיה של אובייקטים שהם צאצאים של סוג האובייקט שצוין.

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

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

כדי לבצע את ההקצאה המאוחרת הזו, יש לקרוא למשמיד כחלק מהתחביר המורחב של הליך Dispose:

Dispose(P, Done);

(קריאה למשמיד מחוץ להליך Dispose לא מקצה זיכרון כלל.) מה שבאמת קורה כאן הוא שאוסף האשפה של האובייקט שעליו מצביע P מבוצע כשיטה רגילה. עם זאת, ברגע שהפעולה האחרונה הושלמה, המשמיד מחפש את גודל היישום של הסוג שלו ב-TCM ומעביר את הגודל לנוהל Dispose. הליך Dispose מסיים את התהליך על ידי מחיקת המספר הנכון של בתים של ה-heap space ש(הרווח) היה שייך בעבר ל-P^. מספר הבתים שיש לשחרר יהיה נכון ללא קשר אם P הצביע על מופע מסוג TSalaried, או אם הוא הצביע על אחד מסוגי הצאצא של הסוג TSalaried, כגון TCommissioned.

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

destructorAnObject.Done;

להתחיל

הסוף;

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

4. שיטות וירטואליות

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

להלן האובייקטים מהמשכורת לדוגמה, וירטואליים כהלכה:

סוּג

PEmployee = ^TEmployee;

עובד עבודה = חפץ

שם, כותרת: מחרוזת[25];

תעריף: אמיתי;

הבנאי Init(AName, ATitle: String; ARate: Real);

פונקציה GetPayAmount: אמיתי; וירטואלי;

function GetName : מחרוזת;

function GetTitle : מחרוזת;

function GetRate : Real;

הליך הצג; וירטואלי;

הסוף;

PHourly = ^THourly;

THourly = object(TEmployee);

זמן: מספר שלם;

הבנאי Init(AName, ATitle: מחרוזת; ARate: אמיתי; זמן: מספר שלם);

פונקציה GetPayAmount: אמיתי; וירטואלי;

function GetTime: מספר שלם;

הסוף;

PSalaried = ^TSalaried;

TSalaried = object(TEmployee);

פונקציה GetPayAmount: אמיתי; וירטואלי;

הסוף;

Pcommissioned = ^Tcommissioned;

TCommissioned = object(Laried);

עמלה: אמיתי;

סכום מכירה: אמיתי;

הבנאי Init(AName, ATitle: String; ARate,

ACommission, ASalesmount: Real);

פונקציה GetPayAmount: אמיתי; וירטואלי;

הסוף;

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

לכל סוג אובייקט שיש לו שיטות וירטואליות חייב להיות בנאי.

אזהרה

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

שים לב

עבור בוני אובייקטים, מומלץ להשתמש במזהה Init.

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

היה

FBee, GBee: Bee; { צור שני מופעי דבורה }

להתחיל

FBee.Init(5, 9) { קורא בנאי עבור FBee }

GBee := FBee; { Gbee אינו חוקי! }

הסוף;

מה בעצם יוצר קונסטרוקטור? כל סוג אובייקט מכיל משהו שנקרא טבלת מתודות וירטואלית (VMT) בקטע הנתונים. ה-TVM מכיל את גודל סוג האובייקט, ולכל שיטה וירטואלית, מצביע לקוד שמבצע שיטה זו. בנאי יוצר קשר בין מימוש הקורא של האובייקט לבין סוג ה-TCM של האובייקט.

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

5. שדות נתוני אובייקט ופרמטרים של שיטה פורמלית

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

הליך CrunchIt(Crunchee: MyDataRec, Crunchby,

ErrorCode: מספר שלם);

היה

א,ב: char;

ErrorCode: מספר שלם;

להתחיל

.

.

.

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

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

הרצאה מס' 13. תאימות סוגי אובייקטים

1. אנקפסולציה

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

לדוגמה, האובייקטים TEmployee ו-THourly נכתבים בצורה כזו שאין שום צורך לגשת ישירות לשדות הנתונים הפנימיים שלהם:

סוג

עובד עבודה = חפץ

שם, כותרת: מחרוזת[25];

תעריף: אמיתי;

procedure Init(AName, ATitle: string; ARate: Real);

function GetName : מחרוזת;

function GetTitle : מחרוזת;

function GetRate : Real;

function GetPayAmount: אמיתי;

הסוף;

THourly = object(TEmployee)

זמן: מספר שלם;

הליך Init(AName, ATitle: מחרוזת; ARate:

אמיתי, זמן: מספר שלם);

function GetPayAmount: אמיתי;

הסוף;

יש כאן רק ארבעה שדות נתונים: שם, כותרת, קצב וזמן. השיטות GetName ו-GetTitle מציגות את שם המשפחה והתפקיד של העובד, בהתאמה. שיטת GetPayAmount משתמשת ב-Rate, ובמקרה של עבודה THourly and Time כדי לחשב את כמות התשלומים לעבודה. אין עוד צורך להתייחס ישירות לשדות הנתונים הללו.

בהנחה שקיומו של מופע AnHourly מסוג THourly, נוכל להשתמש בסט של שיטות כדי לתפעל שדות נתונים של AnHourly כך:

עם לעשות לפי שעה

להתחיל

אינית (אלכסנדר פטרוב, מפעיל מלגזות' 12.95, 62);

{מציג את שם המשפחה, המיקום וכמות התשלומים}

הצג;

הסוף;

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

2. הרחבת חפצים

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

הבה נגדיר סוג ילד של TEmployee המייצג עובד שמשולם לו תעריף שעתי בדוגמה הבאה:

const

PayPeriods = 26; { תקופות תשלום }

סף הארכה = 80; { לתקופת התשלום }

OvertimeFactor = 1.5; { תעריף לשעה }

סוג

THourly = object(TEmployee)

זמן: מספר שלם;

הליך Init(AName, ATitle: מחרוזת; ARate:

אמיתי, זמן: מספר שלם);

function GetPayAmount: אמיתי;

הסוף;

הליך THourly.Init(AName, ATitle: string;

ARate: אמיתי, זמן: מספר שלם);

להתחיל

TEmployee.Init(AName, ATitle, ARate);

זמן := ATime;

הסוף;

function THourly.GetPayAmount: אמיתי;

היה

שעות נוספות: מספר שלם;

להתחיל

שעות נוספות := זמן - סף שעות נוספות;

אם הארכה > 0 אז

GetPayAmount := RoundPay(סף שעות נוספות * תעריף +

דרג שעות נוספות * גורם שעות נוספות * שיעור)

אחר

GetPayAmount := RoundPay (זמן * תעריף)

הסוף;

אדם שמקבל תעריף שעתי הוא עובד: יש לו את כל מה שמשמש להגדרת אובייקט העובד (שם, תפקיד, תעריף), ורק סכום הכסף שמקבל השעה תלוי בכמה שעות עבד במהלך התקופה לתשלום. לפיכך, THourly דורש גם שדה זמן.

מכיוון ש-THourly מגדיר שדה זמן חדש, האתחול שלו דורש שיטת Init חדשה המאתחלת גם את השדות בזמן וגם את השדות שעברו בירושה. במקום להקצות ערכים ישירות לשדות בירושה כמו שם, כותרת ושיעור, למה לא להשתמש מחדש בשיטת האתחול של אובייקט ה-TEmployee (מתואר בהצהרה הראשונה של THourly Init).

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

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

לאחר קריאה ל-TEmployee.Init, THourly.Init יכול לבצע אתחול משלו, שבמקרה זה מורכב רק מהקצאת הערך המועבר ב-ATime.

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

שיטת משכורת. GetPayAmount צריכה לחלק את התעריף של העובד רק במספר התשלומים בכל שנה (בדוגמה שלנו).

עובדי היחידה;

ממשק

const

PayPeriods = 26; {בשנה}

סף הארכה = 80; {עבור כל תקופת תשלום}

OvertimeFactor=1.5; {הגדלה כנגד תשלום רגיל}

סוג

עובד עבודה = חפץ

שם, כותרת: מחרוזת[25];

תעריף: אמיתי;

procedure Init(AName, ATitle: string; ARate: Real);

function GetName : מחרוזת;

function GetTitle : מחרוזת;

function GetRate : Real;

function GetPayAmount: אמיתי;

הסוף;

THourly = object(TEmployee)

זמן: מספר שלם;

הליך Init(AName, ATitle: מחרוזת; ARate:

אמיתי, זמן: מספר שלם);

function GetPayAmount: אמיתי;

פונקציה GetTime: אמיתי;

הסוף;

TSalaried = object(TEmployee)

function GetPayAmount: אמיתי;

הסוף;

TCommissioned = אובייקט (TSalaried)

עמלה: אמיתי;

סכום מכירה: אמיתי;

הבנאי Init(AName, ATitle: String; ARate,

ACommission, ASalesmount: Real);

function GetPayAmount: אמיתי;

הסוף;

הפעלה

function RoundPay(שכר: אמיתי): אמיתי;

{round up payouts to ignore amounts less than

יחידה כספית}

להתחיל

RoundPay := Trunc(Wages * 100) / 100;

.

.

.

TEmployee הוא החלק העליון בהיררכיית האובייקטים שלנו ומכיל את שיטת GetPayAmount הראשונה.

function TEmployee.GetPayAmount : אמיתי;

להתחיל

RunError(211); { תן שגיאת זמן ריצה }

הסוף;

זה עשוי להפתיע שהשיטה נותנת שגיאת זמן ריצה. אם נקרא Employee.GetPayAmount, מתרחשת שגיאה בתוכנית. למה? מכיוון ש-TEmployee הוא העליון בהיררכיית האובייקטים שלנו ואינו מגדיר עובד אמיתי; לכן, אף אחת משיטות ה-TEmployee אינה נקראת בצורה מסוימת, למרות שהן עשויות לעבור בירושה. כל העובדים שלנו הם לפי שעה, בשכר או בעבודת יד. שגיאת זמן ריצה מפסיקה את הפעלת התוכנית ומוציאה 211, התואמת להודעת שגיאה הקשורה לקריאת שיטה מופשטת (אם התוכנית קוראת בטעות ל-TEmployee.GetPayAmount).

להלן שיטת THourly.GetPayAmount, שלוקחת בחשבון דברים כמו תשלום שעות נוספות, שעות עבודה וכו'.

function THourly.GetPayAMount: אמיתי;

היה

שעות נוספות: מספר שלם;

להתחיל

שעות נוספות := זמן - סף שעות נוספות;

אם הארכה > 0 אז

GetPayAmount := RoundPay(סף שעות נוספות * תעריף +

דרג שעות נוספות * גורם שעות נוספות * שיעור)

אחר

GetPayAmount := RoundPay (זמן * תעריף)

הסוף;

שיטת TSalaried.GetPayAmount היא הרבה יותר פשוטה; להמר בו

חלקי מספר התשלומים:

function TSalaried.GetPayAmount : אמיתי;

להתחיל

GetPayAmount := RoundPay(Rate / PayPeriods);

הסוף;

אם תסתכל על שיטת TCommissioned.GetPayAmount, תראה שהיא קוראת ל-TSalaried.GetPayAmount, מחשבת את העמלה ומוסיפה אותה לערך המוחזר על ידי שיטת TSalaried. GetPayAmount.

פונקציה TСommissioned.GetPayAmount: אמיתי;

להתחיל

GetPayAmount := RoundPay(TSalaried.GetPayAmount +

עמלה * סכום מכירה);

הסוף;

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

3. תאימות סוגי אובייקטים

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

תאימות סוגים מורחבת זו לובשת שלוש צורות:

1) בין מימושים של אובייקטים;

2) בין מצביעים למימושי אובייקט;

3) בין פרמטרים פורמליים לממשיים.

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

לדוגמה, TSalaried הוא ילד של TEmployee ו-TSalaried הוא ילד של TSalaried. עם זאת בחשבון, שקול את התיאורים הבאים:

סוּג

PEmployee = ^TEmployee;

PSalaried = ^TSalaried;

Pcommissioned = ^Tcommissioned;

היה

AnEmployee: TEmployee;

ASalaried: TSalaried;

Pcommissioned: TCommissioned;

TEmployeePtr: PEmployee;

TSalariedPtr: PSalaried;

TCommissionedPtr: Pcommissioned;

תחת תיאורים אלה, האופרטורים הבאים תקפים

משימות:

AnEmployee :=משכיר;

ASalaried := ACommissioned;

TCommissionedPtr := ACommissioned;

שים לב

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

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

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

AnEmployee:= ACommissioned;

רק השדות Name, Title ו-Rate מ-ACommissioned יועתקו ל-AnEmployee, שכן אלו הם השדות היחידים המשותפים ל-TCommissioned ו-TEmployee. תאימות סוגים פועלת גם בין מצביעים לסוגי אובייקטים, ועוקבת אחר אותם כללים כלליים כמו עבור יישומי אובייקט. ניתן להקצות מצביע לילד למצביע להורה. בהתחשב בהגדרות הקודמות, הקצאות המצביעים הבאות תקפות:

TSalariedPtr:= TCommissionedPtr;

TEmployeePtr:= TSalariedPtr;

TEmployeePtr:= PCommissionedPtr;

זכור שאסור להקצות הפוך!

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

הליך CalcFedTax(קורבן: TSalaried);

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

הערה:

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

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

הליך Worker.Add(AWorker: PSalared);

סוגי פרמטרים חוקיים יהיו אז PSalaried או Pcommissioned, אך לא PEmployee.

הרצאה מס' 14. אסמבלר

1. על אסמבלר

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

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

פתרון באמת של בעיות הקשורות לחומרה (או, אפילו יותר, בעיות הקשורות לחומרה, כמו זירוז תוכנית, למשל) הוא בלתי אפשרי ללא ידע ב-Assembler.

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

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

אורז. 1. תרשים מבני של מחשב אישי

2. דגם תוכנה של המיקרו-מעבד

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

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

ניתן לחלק את המאגרים הללו לשתי קבוצות גדולות:

1) 6 רישומי משתמשים;

2) 16 אוגרי מערכת.

3. רישומי משתמשים

כפי שהשם מרמז, רישומי משתמשים נקראים מכיוון שהמתכנת יכול להשתמש בהם בעת כתיבת התוכניות שלו. אוגרים אלה כוללים (איור 2):

1) שמונה אוגרים של 32 סיביות שיכולים לשמש מתכנתים לאחסון נתונים וכתובות (הם נקראים גם אוגרים למטרות כלליות (RON)):

eax/ax/ah/al;

ebx/bx/bh/bl;

edx/dx/dh/dl;

ecx/cx/ch/cl;

ebp/bp;

esi/si;

אדי/די;

esp/sp.

2) שישה אוגרי מקטעים: cs, ds, ss, es, fs, gs;

3) אוגרי סטטוס ושליטה:

דגלים אוגרות דגלים/דגלים;

אוגר מצביע פקודה eip/ip.

אורז. 2. משתמש רושם

רבים מהרישומים הללו ניתנים בקו נטוי. אלו אינם אוגרים שונים - הם חלקים מאוגר אחד גדול של 32 סיביות. ניתן להשתמש בהם בתוכנית כאובייקטים נפרדים.

4. רישומים כלליים

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

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

1) eax/ax/ah/al (אוגר מצבר) - סוללה. משמש לאחסון נתוני ביניים. בפקודות מסוימות, השימוש ברישום זה הוא חובה;

2) ebx/bx/bh/bl (בסיס אוגר) - אוגר בסיס. משמש לאחסון כתובת הבסיס של אובייקט כלשהו בזיכרון;

3) ecx/cx/ch/cl (אוגר ספירה) - אוגר מונה. הוא משמש בפקודות שמבצעות כמה פעולות שחוזרות על עצמן. השימוש בו לרוב מרומז ומוסתר באלגוריתם של הפקודה המתאימה.

לדוגמה, פקודת ארגון הלולאה, בנוסף להעברת השליטה לפקודה הממוקמת בכתובת מסוימת, מנתחת ומפחיתה את הערך של האוגר esx/cx באחד;

4) edx/dx/dh/dl (מאגר נתונים) - אוגר נתונים.

בדיוק כמו האוגר eax/ax/ah/al, הוא מאחסן נתוני ביניים. פקודות מסוימות דורשות שימוש בה; עבור פקודות מסוימות זה קורה באופן מרומז.

שני האוגרים הבאים משמשים לתמיכה במה שנקרא פעולות שרשרת, כלומר פעולות המעבדות ברצף שרשראות של אלמנטים, שכל אחד מהם יכול להיות באורך של 32, 16 או 8 סיביות:

1) esi/si (מאגר אינדקס מקור) - אינדקס מקור.

אוגר זה בפעולות שרשרת מכיל את הכתובת הנוכחית של האלמנט בשרשרת המקור;

2) edi/di (register Destination Index) - אינדקס של המקבל (הנמען). פנקס זה בפעולות שרשרת מכיל את הכתובת הנוכחית בשרשרת היעד.

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

1) esp/sp (Stack Pointer Register) - אוגר מצביע מחסנית. מכיל מצביע לראש הערימה בקטע הערימה הנוכחי.

2) ebp/bp (Base Pointer register) - אוגר מצביע בסיס של מסגרת מחסנית. נועד לארגן גישה אקראית לנתונים בתוך הערימה.

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

5. פנקסי פלחים

ישנם שישה אוגרי מקטעים במודל תוכנת המיקרו-מעבד: cs, ss, ds, es, gs, fs.

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

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

המיקרו-מעבד תומך בסוגי המקטעים הבאים.

1. קטע קוד. מכיל פקודות תוכנית. כדי לגשת לקטע זה, נעשה שימוש ב-cs register (code segment register) - אוגר קוד המקטע. הוא מכיל את הכתובת של מקטע הוראות המכונה שאליו יש למיקרו-מעבד גישה (כלומר, הוראות אלה נטענות בצינור המיקרו-מעבד).

2. פלח נתונים. מכיל את הנתונים המעובדים על ידי התוכנית. כדי לגשת למקטע זה, נעשה שימוש ב-ds (register data segment) - אוגר נתוני סגמנט המאחסן את הכתובת של מקטע הנתונים של התוכנית הנוכחית.

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

4. פלח נתונים נוספים. באופן מרומז, האלגוריתמים לביצוע רוב הוראות המכונה מניחים שהנתונים שהם מעבדים ממוקמים בקטע הנתונים, שכתובתו נמצאת ב-ds segment register. אם לתוכנית אין מספיק פלח נתונים אחד, אז יש לה הזדמנות להשתמש בעוד שלושה מקטעי נתונים נוספים. אבל בניגוד למקטע הנתונים הראשי, שכתובתו כלולה ב-ds segment register, בעת שימוש בקטעי נתונים נוספים, יש לציין את הכתובות שלהם במפורש באמצעות קידומות הגדרה מחדש של מקטעים בפקודה. כתובות של מקטעי נתונים נוספים חייבות להיכלל ברגיסטרים es, gs, fs (אוגרי מקטעי הרחבה).

6. אוגרי סטטוס ובקרה

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

1) דגלים אוגרות דגלים;

2) אוגר מצביע פקודה eip/ip.

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

1. eflags/flags (אוגר דגלים) - פנקס דגלים. עומק הסיביות של eflags/דגלים הוא 32/16 סיביות. לסיביות בודדות של אוגר זה יש מטרה פונקציונלית ספציפית והן נקראות דגלים. החלק התחתון של פנקס זה זהה לחלוטין למאגר הדגלים לשנת 18086. איור 3 מציג את התוכן של פנקס האפלגים.

אורז. 3. תוכן פנקס האפלגים

בהתאם לאופן השימוש בהם, ניתן לחלק את הדגלים של מאגר האפלגים/דגלים לשלוש קבוצות:

1) שמונה דגלי סטטוס.

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

2) דגל בקרה אחד.

מסומן df (דגל ספרייה). הוא ממוקם בסיביות 10 של אוגר eflags ומשמש על ידי פקודות משורשרות. הערך של דגל df קובע את כיוון העיבוד של אלמנט אחר אלמנט בפעולות אלו: מתחילת המחרוזת ועד הסוף (df = 0) או להיפך, מסוף המחרוזת לתחילתה (df = 1). ישנן פקודות מיוחדות לעבודה עם דגל df: eld (הסר את דגל df) ו-std (הגדר את דגל df). השימוש בפקודות אלו מאפשר לך לכוונן את דגל ה-df בהתאם לאלגוריתם ולוודא שהמונים מוגדלים או מופחתים באופן אוטומטי בעת ביצוע פעולות על מחרוזות.

3) חמישה דגלי מערכת.

הם שולטים ב-I/O, פסיקות הניתנות למסיכה, איתור באגים, החלפת משימות ומצב וירטואלי 8086. לא מומלץ לתוכניות אפליקציות לשנות את הדגלים הללו שלא לצורך, מכיוון שהדבר יגרום להפסקת התוכנית ברוב המקרים. טבלה 2 מפרטת את דגלי המערכת ומטרתם.

טבלה 1. דגלי מצב טבלה 2. דגלי מערכת

2. eip/ip (Instraction Pointer register) - אוגר מצביע הוראות. אוגר ה-eip/ip הוא ברוחב 32/16 סיביות ומכיל את ההיסט של ההוראה הבאה שתתבצע ביחס לתוכן של אוגר המקטע cs בקטע ההוראה הנוכחי. אוגר זה אינו נגיש ישירות למתכנת, אך ערכו נטען ומשתנה על ידי פקודות בקרה שונות, הכוללות פקודות לקפיצות מותנות ובלתי מותנות, קריאה לפרוצדורות וחזרה מהליכים. התרחשות של פסיקות משנה גם את אוגר ה-eip/ip.

הרצאה מס' 15. נרשמים

1. אוגרי מערכת מיקרו-מעבדים

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

ניתן לחלק את אוגרי המערכת לשלוש קבוצות:

1) ארבעה אוגרי בקרה;

2) ארבעה אוגרים של כתובות מערכת;

3) שמונה אוגרי ניפוי באגים.

2. אוגרי בקרה

קבוצת אוגרי הבקרה כוללת ארבעה אוגרים: cr0, cr1, cr2, cr3. אוגרים אלו מיועדים לבקרת מערכת כללית. אוגרי בקרה זמינים רק לתוכניות עם רמת הרשאה 0.

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

האוגר cr0 מכיל דגלי מערכת השולטים במצבי הפעולה של המיקרו-מעבד ומשקפים את מצבו באופן גלובלי, ללא קשר למשימות הספציפיות המבוצעות.

מטרת דגלי המערכת:

1) pe (Protect Enable), סיביות 0 - אפשר את מצב הפעולה המוגן. המצב של דגל זה מראה באיזה משני המצבים - אמיתי (pe = 0) או מוגן (pe = 1) - המיקרו-מעבד פועל בזמן נתון;

2) mp (Math Present), bit 1 - נוכחות של מעבד משותף. תמיד 1;

3) ts (Task Switched), סיביות 3 - החלפת משימות. המעבד מגדיר אוטומטית סיביות זו כאשר הוא עובר למשימה אחרת;

4) am (מסכת יישור), סיביות 18 - מסכת יישור. סיביות זו מאפשרת (am = 1) או משביתה (am = 0) בקרת יישור;

5) cd (השבתת מטמון), סיביות 30 - השבתת זיכרון מטמון.

באמצעות סיביות זו, אתה יכול להשבית (cd =1) או לאפשר (cd = 0) את השימוש במטמון הפנימי (המטמון ברמה הראשונה);

6) pg (PaGing), סיביות 31 - אפשר (pg =1) או השבת (pg = 0) איתור.

הדגל משמש במודל ההחלפה של ארגון זיכרון.

האוגר cr2 משמש בהחלפת RAM כדי לרשום את המצב שבו ההוראה הנוכחית ניגשה לכתובת הכלולה בדף זיכרון שאינו נמצא כעת בזיכרון.

במצב כזה, מתרחש חריג מספר 14 במיקרו-מעבד, והכתובת הליניארית של 32 סיביות של ההוראה שגרמה לחריג זה נכתבת לרשום cr2. עם מידע זה, מטפל החריגים 14 קובע את העמוד הרצוי, מחליף אותו לזיכרון ומחדש את הפעולה הרגילה של התוכנית;

האוגר cr3 משמש גם לזיכרון ההחלפה. זהו מה שנקרא מרשם ספריית העמודים ברמה הראשונה. הוא מכיל את כתובת הבסיס הפיזית של 20 סיביות של ספריית הדפים של המשימה הנוכחית. ספרייה זו מכילה 1024 מתארים של 32 סיביות, שכל אחד מהם מכיל את הכתובת של טבלת הדפים ברמה השנייה. בתורו, כל אחת מטבלאות העמודים ברמה השנייה מכילה 1024 מתארים של 32 סיביות המטפלים במסגרות עמודים בזיכרון. גודל מסגרת העמוד הוא 4 KB.

3. רישומי כתובות המערכת

אוגרים אלה נקראים גם אוגרי ניהול זיכרון.

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

1) גלובלי - משותף לכל המשימות;

2) מקומי - נפרד לכל משימה.

הפרדה זו מסבירה את נוכחותם של אוגרי המערכת הבאים בארכיטקטורת המיקרו-מעבד:

1) האוגר של טבלת המתאר הגלובלית gdtr (Global Descriptor Table Register), בעל גודל של 48 סיביות ומכיל כתובת בסיס של 32 סיביות (סיביות 16-47) של טבלת המתאר הגלובלית GDT ו-16 סיביות (סיביות 0-15) ערך גבול, שהוא הגודל בבתים של טבלת GDT;

2) אוגר טבלת המתאר המקומי ldtr (Local Descriptor Table Register), בעל גודל של 16 סיביות ומכיל את מה שנקרא בורר המתאר של טבלת התיאורים המקומית LDT בורר זה הוא מצביע בטבלת GDT, המתאר את קטע המכיל את טבלת התיאורים המקומית LDT;

3) האוגר של טבלת מתאר הפסיקות idtr (מאגר מתאר פסיקה), בעל גודל של 48 סיביות ומכיל כתובת בסיס של 32 סיביות (סיביות 16-47) של טבלת מתאר הפסיקות IDT ו-16 סיביות (סיביות 0-15) ערך גבול, שהוא גודל בבתים של טבלת IDT;

4) 16-bit task register tr (Task Register), אשר, כמו אוגר ldtr, מכיל בורר, כלומר מצביע לתיאור בטבלת GDT. מתאר זה מתאר את מצב מקטע המשימות הנוכחי (TSS). קטע זה נוצר עבור כל משימה במערכת, יש לו מבנה מוסדר בקפדנות ומכיל את ההקשר (המצב הנוכחי) של המשימה. המטרה העיקרית של מקטעי TSS היא לשמור את המצב הנוכחי של משימה ברגע המעבר למשימה אחרת.

4. ​​ניפוי רשומות

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

לרשמים dr0, dr1, dr2, dr3 יש רוחב של 32 סיביות והם מיועדים להגדיר את הכתובות הליניאריות של ארבע נקודות שבירה. המנגנון המשמש במקרה זה הוא הבא: כל כתובת שנוצרת על ידי התוכנית הנוכחית מושווה עם הכתובות באוגרים dr0...dr3, ואם יש התאמה, נוצר חריג באגים עם מספר 1.

Register dr6 נקרא אוגר מצב ניפוי הבאגים. הסיביות במאגר הזה נקבעות לפי הסיבות שגרמו לחריג האחרון מספר 1 להתרחש.

אנו מפרטים את הקטעים הללו ואת מטרתם:

1) b0 - אם ביט זה מוגדר ל-1, אז החריגה האחרונה (הפסקה) התרחשה כתוצאה מהגעה לנקודת המחסום שהוגדרה ברישום dr0;

2) b1 - דומה ל-b0, אך עבור מחסום ברישום dr1;

3) b2 - דומה ל-b0, אך עבור מחסום ברישום dr2;

4) bЗ - דומה ל-b0, אך עבור מחסום ברישום dr3;

5) bd (סיביות 13) - משמשת להגנה על אוגרי הבאגים;

6) bs (bit 14) - מוגדר ל-1 אם חריג 1 נגרם על ידי מצב הדגל tf = 1 במאגר eflags;

7) bt (סיביות 15) מוגדרת ל-1 אם חריג 1 נגרם על ידי מעבר למשימה עם סיבית ה- trap מוגדרת ב-TSS t = 1.

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

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

1) מיקום רישום מחסום - רק במשימה הנוכחית או בכל משימה. סיביות אלו תופסות את 8 הסיביות התחתונות של האוגר dr7 (2 סיביות לכל נקודת שבירה (למעשה נקודת שבירה) שנקבעה על ידי האוגרים dr0, dr1, dr2, dr3, בהתאמה).

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

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

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

הרצאה מס' 16. תוכניות אסמבלר

1. מבנה התוכנית ב-assembler

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

הצהרות הרכבה הן מארבעה סוגים:

1) פקודות או הוראות, שהן אנלוגים סמליים לפקודות מכונה. במהלך תהליך התרגום, הוראות ההרכבה מומרות לפקודות המתאימות של ערכת הוראות המיקרו-מעבד;

2) פקודות מאקרו. מדובר במשפטים של טקסט התוכנית שמתגבשים בצורה מסוימת ומוחלפים במשפטים אחרים במהלך השידור;

3) הנחיות, המהוות אינדיקציה למתרגם האסמבלר לבצע פעולות מסוימות. להנחיות אין מקבילות בייצוג מכונה;

4) שורות הערה המכילות תווים כלשהם, כולל אותיות האלפבית הרוסי. המתרגם מתעלם מהתגובות.

2. תחביר הרכבה

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

אורז. 4. פורמט משפט אסמבלר

אורז. 5. פורמט הנחיות

אורז. 6. פורמט פקודות ופקודות מאקרו

על הציורים האלה:

1) שם תווית - מזהה, שערכו הוא הכתובת של הביט הראשון של המשפט של קוד המקור של התוכנית שהוא מציין;

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

3) קוד פעולה (COP) והנחיה הם ייעודים מנמוניים של הוראת המכונה, הנחיית המאקרו או הנחיית המתרגם המתאימה;

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

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

התווים המותרים בעת כתיבת טקסט של תוכניות הם:

1) כל האותיות הלטיניות: A - Z, a - z. במקרה זה, אותיות רישיות וקטנות נחשבות שוות ערך;

2) מספרים מ-0 עד 9;

3) סימנים ?, @, S, _, &;

4) מפרידים.

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

האסימונים הם כדלקמן.

1. מזהים - רצפים של תווים חוקיים המשמשים לייעוד אובייקטי תוכנה כגון קודי פעולה, שמות משתנים ושמות תוויות. הכלל לכתיבת מזהים הוא כדלקמן: מזהה יכול להכיל תו אחד או יותר. בתור תווים, אתה יכול להשתמש באותיות של האלפבית הלטיני, מספרים וכמה תווים מיוחדים - _, ?, $, @. מזהה לא יכול להתחיל עם תו ספרתי. אורך המזהה יכול להיות עד 255 תווים, אם כי המתרגם מקבל רק את 32 התווים הראשונים ומתעלם מהשאר. אתה יכול להתאים את אורך המזהים האפשריים באמצעות אפשרות שורת הפקודה mv. בנוסף, ניתן לומר למתרגם להבחין בין אותיות רישיות לאותיות קטנות או להתעלם מההבדל ביניהן (מה שנעשה כברירת מחדל). לשם כך נעשה שימוש באפשרויות שורת הפקודה /mu, /ml, /mx.

2. שרשרות תווים - רצפים של תווים המוקפים במרכאות בודדות או כפולות.

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

1) מספרים עשרוניים אינם דורשים זיהוי של תווים נוספים, לדוגמה, 25 או 139;

2) כדי לזהות מספרים בינאריים בטקסט המקור של התוכנית, יש צורך לשים את "b" הלטינית לאחר כתיבת האפסים והאלה המרכיבים אותם, למשל, 10010101 b;

3) למספרים הקסדצימליים יש יותר מוסכמות בעת כתיבה:

א) ראשית, הם מורכבים ממספרים 0...9, אותיות קטנות ואותיות גדולות של האלפבית הלטיני a, b, c, d, e, Gili D B, C, D, E, E

ב) שנית, המתרגם עלול להתקשות בזיהוי מספרים הקסדצימליים בשל העובדה שהם יכולים להיות מורכבים רק מספרות 0...9 (לדוגמה, 190845) או להתחיל באות של האלפבית הלטיני (לדוגמה, efl5 ). על מנת "להסביר" למתרגם שאסימון נתון אינו מספר עשרוני או מזהה, על המתכנת להדגיש את המספר הקסדצימלי בצורה מיוחדת. כדי לעשות זאת, כתוב את האות הלטינית "h" בסוף רצף הספרות הקסדצימליות המרכיבות מספר הקסדצימלי. זה חובה. אם מספר הקסדצימלי מתחיל באות, אז נכתב לפניו אפס מוביל: 0 efl5 h.

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

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

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

הבה נבחן ביתר פירוט את המאפיינים של האופרנדים בסיווג הבא:

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

2) אופרנדים של כתובת, ציין את המיקום הפיזי של האופרנד בזיכרון על ידי ציון שני מרכיבים של הכתובת: מקטע והיסט (איור 7);

אורז. 7. תחביר של תיאור אופרנדים של כתובת

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

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

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

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

4) אופרנד רישום הוא רק שם רישום. בתוכנית אסמבלר, אתה יכול להשתמש בשמות של כל האוגרים למטרות כלליות ורוב אוגרי המערכת;

5) אופרנדים בסיס ואינדקס. סוג אופרנד זה משמש ליישום בסיס עקיף, כתובת אינדקס עקיפה, או שילובים והרחבות שלהם;

6) אופרנדים מבניים משמשים לגישה לאלמנט ספציפי מסוג נתונים מורכב הנקרא מבנה.

רשומות (בדומה לסוג struct) משמשות לגישה לשדה סיביות של רשומה כלשהי.

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

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

1. אופרטורים אריתמטיים. אלו כוללים:

1) "+" ו-"-" אונריים;

2) בינאריים "+" ו-"-";

3) כפל "*";

4) חלוקת מספרים שלמים "/";

5) קבלת השאר מהחלוקה "מוד".

מפעילים אלה ממוקמים ברמות קדימות 6,7,8 בטבלה 4.

אורז. 8. תחביר של פעולות אריתמטיות

2. אופרטורי Shift מעבירים את הביטוי במספר הסיביות שצוין (איור 9).

אורז. 9. תחביר של מפעילי משמרת

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

אורז. 10. תחביר של אופרטורים להשוואה

טבלה 3. אופרטורים להשוואה

4. אופרטורים לוגיים מבצעים פעולות סיביות על ביטויים (איור 11). ביטויים חייבים להיות מוחלטים, כלומר כאלה, שאת ערכם המספרי ניתן לחשב המתרגם.

אורז. 11. תחביר של אופרטורים לוגיים

5. אופרטור אינדקס []. סוגריים הם גם אופרטור, והמתרגם תופס את נוכחותם כהוראה להוסיף את הערך של expression_1 מאחורי סוגריים אלה עם expression_2 מוקף בסוגריים (איור 12).

אורז. 12. תחביר אופרטור אינדקס

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

6. אופרטור ההגדרה מחדש מסוג ptr משמש כדי להגדיר מחדש או להכשיר את סוג התווית או המשתנה המוגדרים על ידי ביטוי (איור 13).

הסוג יכול לקבל אחד מהערכים הבאים: byte, word, dword, qword, tbyte, near, far.

אורז. 13. תחביר של אופרטור הגדרה מחדש של סוג

7. אופרטור ההגדרה מחדש של המקטע ":" (נקודתיים) מאלץ את החישוב של כתובת פיזית ביחס לרכיב פלח ספציפי: "שם מקטע מקטע", "שם מקטע" מהנחיית SEGMENT המקבילה, או "שם קבוצה" (איור. 14). כאשר דיברנו על פילוח, דיברנו על כך שהמיקרו-מעבד ברמת החומרה תומך בשלושה סוגים של מקטעים - קוד, מחסנית ונתונים. מהי תמיכת החומרה הזו? לדוגמה, כדי לבחור את ביצוע הפקודה הבאה, המיקרו-מעבד חייב בהכרח להסתכל על התוכן של אוגר המקטע cs ורק אותו. והרישום הזה, כידוע, מכיל את הכתובת הפיזית (שעדיין לא הוסטה) של תחילת קטע ההוראה. כדי לקבל את הכתובת של הוראה מסוימת, המיקרו-מעבד צריך להכפיל את התוכן של cs ב-16 (שמשמעותו תזוזה בארבע סיביות) ולהוסיף את ערך 20 הסיביות המתקבל לתוכן 16 הסיביות של אוגר ה-ip. בערך אותו דבר קורה כאשר המיקרו-מעבד מעבד את האופרנדים בהוראת המכונה. אם הוא רואה שהאופרנד הוא כתובת (כתובת אפקטיבית שהיא רק חלק מהכתובת הפיזית), אז הוא יודע באיזה קטע לחפש אותו - כברירת מחדל, זה הקטע שכתובת ההתחלה שלו מאוחסנת ב-sectare register ds .

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

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

אורז. 14. תחביר של אופרטור ההגדרה מחדש של המקטע

8. אופרטור מתן השם "."(נקודה) גם מאלץ את המהדר לבצע חישובים מסוימים אם הוא מתרחש בביטוי.

9. האופרטור לקבלת רכיב הקטע של הכתובת של הביטוי seg מחזיר את הכתובת הפיזית של הקטע עבור הביטוי (איור 15), שיכול להיות תווית, משתנה, שם קטע, שם קבוצה או שם סמלי כלשהו. .

אורז. 15. תחביר של האופרטור המקבל רכיב המקטע

10. האופרטור לקבלת ההיסט של הביטוי offset מאפשר לקבל את ערך ההיסט של הביטוי (איור 16) בבייטים ביחס לתחילת הקטע בו מוגדר הביטוי.

אורז. 16. תחביר של אופרטור ה- offset get

כמו בשפות ברמה גבוהה, הביצוע של אופרטורים של אסמבלר בעת הערכת ביטויים מתבצע בהתאם לסדרי העדיפויות שלהם (טבלה 4). פעולות עם אותה עדיפות מבוצעות ברצף משמאל לימין. שינוי סדר הביצוע אפשרי על ידי הצבת סוגריים בעלי העדיפות הגבוהה ביותר.

טבלה 4. מפעילים וקדימותם

3. הוראות פילוח

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

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

1) עם קטע קוד אחד;

2) עם קטע מחסנית אחד;

3) עם מקטע נתונים אחד;

4) עם שלושה מקטעי נתונים נוספים.

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

התיאור התחבירי של קטע ב-assembler הוא המבנה המוצג באיור 17:

אורז. 17. תחביר תיאור הפלחים

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

שקול אותם בפירוט רב יותר.

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

1) BYTE - יישור לא מבוצע. קטע יכול להתחיל בכל כתובת זיכרון;

2) WORD - הקטע מתחיל בכתובת שהיא כפולה של שתיים, כלומר הביט האחרון (הפחות משמעותי) של הכתובת הפיזית הוא 0 (מיושר לגבול המילה);

3) DWORD - הקטע מתחיל בכתובת שהיא כפולה של ארבע, כלומר שתי הסיביות האחרונות (הפחות משמעותיות) הן 0 (יישור גבול מילים כפול);

4) PARA - הקטע מתחיל בכתובת שהיא כפולה של 16, כלומר הספרה ההקסדצימלית האחרונה של הכתובת חייבת להיות Oh (יישור לגבול הפסקה);

5) PAGE - הקטע מתחיל בכתובת שהיא כפולה של 256, כלומר שתי הספרות ההקסדצימליות האחרונות חייבות להיות 00h (מיושרות לגבול של עמוד של 256 בתים);

6) MEMPAGE - הקטע מתחיל בכתובת שהיא כפולה של 4 KB, כלומר שלוש הספרות ההקסדצימליות האחרונות חייבות להיות OOOh (הכתובת של דף הזיכרון הבא של 4 KB). סוג היישור המוגדר כברירת מחדל הוא PARA.

2. התכונה combine segment (סוג קומבינטורית) אומרת למקשר כיצד לשלב מקטעים של מודולים שונים בעלי אותו שם. ערכי תכונת שילוב הפלחים יכולים להיות:

1) PRIVATE - הקטע לא ימוזג עם קטעים אחרים בעלי אותו שם מחוץ למודול זה;

2) PUBLIC - גורם למקשר לחבר את כל הקטעים בעלי אותו שם. הקטע הממוזג החדש יהיה שלם ורציף. כל הכתובות (הקזזות) של אובייקטים, וזה עשוי להיות תלוי בסוג הפקודה וקטע הנתונים, יחושבו ביחס לתחילתו של מקטע חדש זה;

3) COMMON - מציב את כל הקטעים עם אותו שם באותה כתובת. כל הקטעים עם השם הנתון יחפפו ויחלקו זיכרון. גודל הקטע המתקבל יהיה שווה לגודל הקטע הגדול ביותר;

4) AT xxxx - מאתר את הקטע בכתובת המוחלטת של הפסקה (פיסקה היא כמות הזיכרון, כפולה של 16; לכן, הספרה ההקסדצימלית האחרונה של כתובת הפסקה היא 0). הכתובת המוחלטת של פסקה ניתנת על ידי xxx. המקשר ממקם את הקטע בכתובת זיכרון נתונה (ניתן להשתמש בזה, למשל, כדי לגשת לזיכרון וידאו או לאזור ROM>), תוך התחשבות בתכונה המשלבת. מבחינה פיזית, זה אומר שהקטע, כאשר הוא נטען לזיכרון, יאתר החל מהכתובת המוחלטת הזו של הפסקה, אך כדי לגשת אליו, יש לטעון את הערך שצוין בתכונה לאוגר המקטע המתאים. כל התוויות והכתובות בקטע שהוגדר כך הן יחסית לכתובת המוחלטת הנתונה;

5) STACK - הגדרה של קטע מחסנית. גורם למקשר לחבר את כל הקטעים בעלי אותו שם ולחשב את הכתובות בקטעים אלו ביחס ל-ss register. הסוג המשולב STACK (מחסנית) דומה לסוג המשולב PUBLIC, אלא שהאוגר ss הוא אוגר המקטע הסטנדרטי עבור מקטעי מחסנית. האוגר sp מוגדר לסוף קטע המחסנית המשורשרת. אם לא צוין קטע מחסנית, המקשר יוציא אזהרה שלא נמצא מקטע מחסנית. אם נוצר מקטע מחסנית ולא נעשה שימוש בסוג STACK המשולב, על המתכנת לטעון במפורש את כתובת המקטע ל-ss register (בדומה ל-ds register).

ברירת המחדל של תכונת השילוב היא PRIVATE.

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

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

1) USE16 - זה אומר שהקטע מאפשר כתובת 16 סיביות. בעת יצירת כתובת פיזית, ניתן להשתמש רק בהיסט של 16 סיביות. בהתאם לכך, פלח כזה יכול להכיל עד 64 KB של קוד או נתונים;

2)USE32 - הקטע יהיה 32 סיביות. בעת יצירת כתובת פיזית, ניתן להשתמש בהיסט של 32 סיביות. לכן, פלח כזה יכול להכיל עד 4 GB של קוד או נתונים.

כל המקטעים שווים בפני עצמם, שכן הנחיות SEGMENT ו-ENDS אינן מכילות מידע על המטרה הפונקציונלית של המקטעים. על מנת להשתמש בהם כקוד, נתונים או מקטעי מחסנית, תחילה עליך ליידע את המתרגם על כך, שעבורו נעשה שימוש בהנחיית ASSUME מיוחדת, בעלת הפורמט המוצג באיור. 18. הנחיה זו אומרת למתרגם איזה קטע קשור לאיזה מאגר קטעים. בתורו, זה יאפשר למתרגם לאגד נכון את השמות הסמליים המוגדרים בקטעים. קשירה של מקטעים לרגלי מקטעים מתבצעת באמצעות האופרנדים של הנחיה זו, שבהן segment_name חייב להיות שם הסגמנט המוגדר בקוד המקור של התוכנית על ידי הוראת SEGMENT או מילת המפתח כלום. אם רק מילת המפתח שום דבר משמשת כאופרנד, אזי ההקצאות הקודמות של אוגר המקטעים מבוטלות, ולכל ששת אוגרי המקטעים בבת אחת. אבל ניתן להשתמש במילת המפתח שום דבר במקום ארגומנט שם הפלח; במקרה זה, הקשר בין המקטע עם שם המקטע לבין מאגר המקטעים המתאים יינתק באופן סלקטיבי (ראה איור 18).

אורז. 18. הנחיית הנחה

עבור תוכניות פשוטות המכילות קטע אחד עבור קוד, נתונים וערימה, נרצה לפשט את התיאור שלה. לשם כך, המתרגמים MASM ו-TASM הציגו את היכולת להשתמש בהנחיות פילוח מפושטות. אבל כאן נוצרה בעיה הקשורה לעובדה שהיה צורך לפצות איכשהו על חוסר היכולת לשלוט ישירות במיקום ובשילוב של מקטעים. לשם כך, יחד עם הנחיות פילוח מפושטות, החלו להשתמש בהנחיה לציון מודל הזיכרון MODEL, אשר החל לשלוט בחלקו על מיקום המקטעים ולבצע את הפונקציות של הוראת ASSUME (לכן, כאשר משתמשים בהוראות פילוח מפושטות, ניתן להשמיט את הנחיית ASSUME). הנחיה זו מחייבת מקטעים, שבמקרה של שימוש בהנחיות פילוח מפושטות, יש להם שמות מוגדרים מראש, עם אוגרי מקטעים (אם כי עדיין צריך לאתחל את ds במפורש).

התחביר של הוראת MODEL מוצג באיור 19.

אורז. 19. תחביר של הוראת MODEL

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

טבלה 5. הוראות הגדרת מקטעים מופשטות

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

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

טבלה 6. מזהים שנוצרו על ידי הוראת MODEL

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

טבלה 7. דגמי זיכרון

הפרמטר "משנה" של הוראת MODEL מאפשר לך לציין כמה תכונות של שימוש במודל הזיכרון שנבחר (טבלה 8).

טבלה 8. משנה מודל זיכרון

הפרמטרים האופציונליים "שפה" ו-"שינוי שפה" מגדירים כמה תכונות של קריאות פרוצדורות. הצורך להשתמש בפרמטרים אלו מתעורר בעת כתיבה וקישור של תוכניות בשפות תכנות שונות.

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

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

הרצאה מס' 17. מבני פיקוד באסמבלר

1. מבנה הוראת מכונה

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

1) מה לעשות? (התשובה לשאלה זו ניתנת על ידי אלמנט הפקודה הנקרא קוד הפעולה (COP).);

2) אובייקטים שעליהם צריך לעשות משהו (אלמנטים אלה נקראים אופרנדים);

3) איך לעשות? (אלמנטים אלה נקראים טיפוסי אופרנדים והם בדרך כלל מרומזים).

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

אורז. 20. פורמט הוראות מכונה

הבה נתאר את המטרה של שדות הוראות המכונה.

1. קידומות.

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

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

א) 2eh - החלפת קטע cs;

ב) 36h - החלפת קטע ss;

ג) 3eh - החלפת קטע ds;

ד) 26h - החלפת קטע es;

ה) 64h - החלפת קטע fs;

ה) 65h - החלפת קטע gs;

2) קידומת ה-bitness של הכתובת מציינת את ה-bitness של הכתובת (32- או 16-bit). לכל הוראה המשתמשת באופרנד כתובת מוקצה רוחב הסיביות של הכתובת של אותו אופרנד. כתובת זו יכולה להיות 16 או 32 סיביות. אם רוחב הכתובת עבור פקודה זו הוא 16 סיביות, זה אומר שהפקודה מכילה היסט של 16 סיביות (איור 20), היא מתאימה להיסט של 16 סיביות של אופרנד הכתובת ביחס לתחילתו של קטע כלשהו. בהקשר של איור 21, היסט זה נקרא הכתובת האפקטיבית. אם הכתובת היא 32 סיביות, זה אומר שהפקודה מכילה היסט של 32 סיביות (איור 20), היא מתאימה להיסט של 32 סיביות של אופרנד הכתובת ביחס לתחילת הקטע, והערך שלה יוצר 32 -ביט היסט בקטע. ניתן להשתמש בקידומת bitness של כתובת כדי לשנות את ברירת המחדל של bitness של כתובת. שינוי זה ישפיע רק על הפקודה שלפניה הקידומת;

אורז. 21. מנגנון היווצרות כתובת פיזית במצב אמיתי

3) קידומת רוחב סיביות אופרנד דומה לקידומת רוחב סיביות של כתובת, אך מציינת את אורך סיביות האופרנד (32 סיביות או 16 סיביות) איתה פועלת ההוראה. מה הם הכללים להגדרת תכונות רוחב סיביות של כתובת ואופרנד כברירת מחדל?

במצב אמיתי ובמצב 18086 וירטואלי, הערכים של תכונות אלה הם 16 סיביות. במצב מוגן, ערכי התכונה תלויים במצב ה-D bit במתארי המקטע הניתנים להפעלה. אם D = 0, ערכי ברירת המחדל של תכונה הם 16 סיביות; אם D = 1, אז 32 סיביות.

ערכי קידומת עבור אופרנד רוחב 66h ורוחב כתובת 67h. עם קידומת סיביות הכתובת של המצב האמיתי, אתה יכול להשתמש בכתובת של 32 סיביות, אך שים לב למגבלת גודל הקטע של 64 קילו-בייט. בדומה לקידומת רוחב כתובת, אתה יכול להשתמש בקידומת אופרנד-רוחב במצב אמיתי כדי לעבוד עם אופרנדים של 32 סיביות (לדוגמה, בהוראות אריתמטיות);

4) קידומת החזרה משמשת עם פקודות שרשרת (פקודות עיבוד שורה). קידומת זו "לולאת" את הפקודה לעיבוד כל רכיבי השרשרת. מערכת הפיקוד תומכת בשני סוגים של קידומות:

א) ללא תנאי (rep - OOh), הכופה על הפקודה המשורשרת לחזור על עצמה מספר מסוים של פעמים;

ב) מותנה (repe/repz - OOh, repne/repnz - 0f2h), אשר בעת לולאה בודקים כמה דגלים, וכתוצאה מהבדיקה מתאפשרת יציאה מוקדמת מהלולאה.

2. קוד פעולה.

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

3. מצב כתובת בתים modr/m.

הערך של בית זה קובע את טופס כתובת האופרנד בשימוש. אופרנדים יכולים להיות בזיכרון ברגיסטר אחד או שניים. אם האופרנד נמצא בזיכרון, אז ה-modr/m byte מציין את הרכיבים (אוגרי offset, base ו-index) המשמשים לחישוב הכתובת האפקטיבית שלו (איור 21). במצב מוגן, ניתן להשתמש בנוסף ב-sib byte (Scale-Index-Base) כדי לקבוע את המיקום של האופרנד בזיכרון. byte modr/m מורכב משלושה שדות (איור 20):

1) שדה המוד קובע את מספר הבתים שתפוסה על ידי כתובת האופרנד בפקודה (איור 20, שדה ההיסט בפקודה). שדה המוד משמש בשילוב עם שדה r/m, המציין כיצד לשנות את הכתובת של אופרנד "הסטת הוראות". לדוגמה, אם mod = 00, זה אומר שאין שדה offset בפקודה, והכתובת של האופרנד נקבעת על פי התוכן של אוגר הבסיס ו(או) האינדקס. אילו אוגרים ישמשו לחישוב הכתובת האפקטיבית נקבעת לפי הערך של בייט זה. אם mod = 01, זה אומר ששדה ההיסט קיים בפקודה, תופס 1 בייט ומשונה על ידי התוכן של הבסיס ו(או) ה-index register. אם mod = 10, זה אומר ששדה ההיסט קיים בפקודה, תופס 2 או 4 בתים (בהתאם לגודל הכתובת המוגדרת כברירת מחדל או קידומת), והוא משתנה על ידי התוכן של אוגר הבסיס ו/או האינדקס. אם mod = 11, זה אומר שאין אופרנדים בזיכרון: הם נמצאים ברגיסטרים. אותו ערך של byte mod משמש כאשר נעשה שימוש באופרנד מיידי בהוראה;

2) שדה reg/cop קובע את האוגר הממוקם בפקודה במקום האופרנד הראשון, או הרחבה אפשרית של ה-opcode;

3) שדה r/m משמש בשילוב עם שדה mod וקובע או את האוגר הממוקם בפקודה במקום האופרנד הראשון (אם mod = 11), או את אוגרי הבסיס והאינדקס המשמשים לחישוב הכתובת האפקטיבית (יחד עם שדה ההיסט בפקודה).

4. סולם בתים - אינדקס - בסיס (בייט sib).

משמש להרחבת אפשרויות ההתייחסות לאופרנדים. נוכחות ה-sib-byte בהוראה למכונה מסומנת על-ידי שילוב של אחד מהערכים 01 או 10 של שדה ה-mod וערך השדה r/m = 100. ה-sib-byte מורכב משלושה שדות:

1) קנה מידה שדות ss. שדה זה מכיל את גורם קנה המידה עבור אינדקס רכיב האינדקס, אשר תופס את 3 הסיביות הבאות של הביט sib. השדה ss יכול להכיל אחד מהערכים הבאים: 1, 2, 4, 8.

בעת חישוב הכתובת האפקטיבית יוכפל התוכן של פנקס האינדקס בערך זה;

2) שדות אינדקס. משמש לאחסון מספר אוגר האינדקס המשמש לחישוב הכתובת האפקטיבית של האופרנד;

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

5. שדה היסט בפקודה.

מספר שלם בסימן 8, 16 או 32 סיביות המייצג, כולו או חלקו (בכפוף לשיקולים לעיל), את הערך של הכתובת האפקטיבית של האופרנד.

6. שדה האופרנד המיידי.

שדה אופציונלי שהוא אופרנד מיידי של 8 סיביות, 16 סיביות או 32 סיביות. הנוכחות של שדה זה באה לידי ביטוי, כמובן, בערך של byte modr/m.

2. שיטות לציון אופרנדים של הוראות

האופרנד מוגדר באופן מרומז ברמת הקושחה

במקרה זה, ההוראה אינה מכילה במפורש אופרנדים. אלגוריתם ביצוע הפקודה משתמש בכמה אובייקטים המוגדרים כברירת מחדל (רגיסטרים, דגלים ב-eflags וכו').

לדוגמה, הפקודות cli ו-sti פועלות באופן מרומז עם הדגל if interrupt ב-eflags register, והפקודה xlat ניגשת באופן מרומז ל-al register ולשורה בזיכרון בכתובת שצוינה על ידי זוג האוגר ds:bx.

האופרנד מצוין בהוראה עצמה (אופרנד מיידי)

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

לדוגמה: mov ax,0ffffti מעביר את הקבוע ההקסדצימלי ffff לתוך ax of register. הפקודה add sum, 2 מוסיפה את תוכן השדה בסכום הכתובת עם המספר השלם 2 וכותבת את התוצאה במקום האופרנד הראשון, כלומר לזיכרון.

האופרנד נמצא באחד הרשמים

אופרנדים של רישום מצוינים לפי שמות הרישום. ניתן להשתמש ברישום:

1) אוגרי 32 סיביות EAX, EBX, ECX, EDX, ESI, EDI, ESP, EUR;

2) אוגרים של 16 סיביות AX, BX, CX, DX, SI, DI, SP, BP;

3) אוגרים של 8 סיביות AH, AL, BH, BL, CH, CL, DH, DL;

4) מקטע רושמת CS, DS, SS, ES, FS, GS.

לדוגמה, ההוראה add ax,bx מוסיפה את התוכן של אוגרים ax ו-bx וכותבת את התוצאה ל-bx. הפקודה dec si מורידה את התוכן של si ב-1.

האופרנד נמצא בזיכרון

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

בתורו, לפנייה עקיפה יש את הזנים הבאים:

1) כתובת בסיס עקיפה; שמו השני הוא כתובת עקיפה לרשום;

2) כתובת בסיס עקיפה עם היסט;

3) כתובת אינדקס עקיפה עם היסט;

4) התייחסות לאינדקס בסיס עקיפה;

5) כתובת אינדקס בסיס עקיפה עם היסט.

האופרנד הוא יציאת I/O

בנוסף למרחב כתובות ה-RAM, המיקרו-מעבד שומר על מרחב כתובת I/O, המשמש לגישה להתקני I/O. מרחב כתובות ה-I/O הוא 64 KB. כתובות מוקצות לכל מכשיר מחשב במרחב זה. ערך כתובת מסוים בתוך מרחב זה נקרא יציאת I/O. מבחינה פיזית, יציאת ה-I/O מתאימה לאוגר חומרה (לא להתבלבל עם אוגר מיקרו-מעבד), שאליו ניתן לגשת באמצעות הוראות אסמבלר מיוחדות פנימה והחוצה.

לדוגמה:

ב-al,60h; הזן בייט מיציאה 60h

רישומים המטופלים על ידי יציאת I/O יכולים להיות ברוחב של 8,16, 32 או XNUMX סיביות, אך רוחב סיביות הרגיסטר קבוע עבור יציאה מסוימת. פקודות היציאה והכניסה פועלות על טווח קבוע של עצמים. מה שנקרא אוגרי מצבר EAX, AX, AL משמשים כמקור מידע או נמען. בחירת האוגר נקבעת על פי מידת היציבות של הפורט. ניתן לציין את מספר היציאה כאופרנד מיידי בהוראות הכניסה והיציאה, או כערך באוגר DX. השיטה האחרונה מאפשרת לך לקבוע באופן דינמי את מספר היציאה בתוכנית.

האופרנד נמצא על הערימה

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

1) רישום - רישום;

2) רישום - זיכרון;

3) זיכרון - רישום;

4) אופרנד מיידי - רישום;

5) אופרנד מיידי - זיכרון.

ישנם חריגים לכלל זה לגבי:

1) שרשרת פקודות שיכולות להעביר נתונים מהזיכרון לזיכרון;

2) פקודות מחסנית שיכולות להעביר נתונים מהזיכרון לערימה שנמצאת גם בזיכרון;

3) פקודות מסוג הכפל, אשר בנוסף לאופרנד המצוין בפקודה, משתמשות גם באופרנד שני, מרומז.

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

3. דרכי פנייה

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

1) פנייה ישירה;

2) התייחסות בסיסית (רשום) עקיפה;

3) כתובת בסיסית עקיפה (אוגר) עם קיזוז;

4) כתובת אינדקס עקיפה עם היסט;

5) התייחסות לאינדקס בסיס עקיפה;

6) כתובת אינדקס בסיס עקיפה עם היסט.

פנייה ישירה

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

פנייה ישירה יכולה להיות משני סוגים.

פנייה ישירה יחסית

משמש להוראות קפיצה מותנית לציון כתובת הקפיצה היחסית. היחסיות של מעבר כזה טמונה בעובדה ששדה ההיסט של הוראת המכונה מכיל ערך של 8, 16 או 32 סיביות, שכתוצאה מפעולת ההוראה יתווסף לתוכן של אוגר מצביע ה-ip/eip. כתוצאה מתוספת זו מתקבלת הכתובת שאליה מתבצע המעבר.

פנייה ישירה מוחלטת

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

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

סוגים אחרים של פניות הם עקיפים. המילה "עקיף" בשם סוגי הפנייה הללו פירושה שרק חלק מהכתובת האפקטיבית יכול להיות בהוראה עצמה, ושאר מרכיביה נמצאים ברגיסטרים, אשר מסומנים על ידי תוכנם על ידי byte modr/m ו, אולי, לפי byte sib.

כתובת עקיפה בסיסית (רישום).

עם הפנייה הזו, הכתובת האפקטיבית של האופרנד יכולה להיות בכל אחד מהאוגרים למטרות כלליות, למעט sp/esp ו-bp/ebp (אלה אוגרים ספציפיים לעבודה עם קטע מחסנית). באופן תחבירי בפקודה, מצב הפנייה הזה מתבטא על ידי הגדר של שם האוגר בסוגריים מרובעים []. לדוגמה, ההוראה mov ax, [ecx] מציבה ב-registers ax את תוכן המילה בכתובת מקטע הנתונים עם ההיסט מאוחסן ב-register esx. מכיוון שניתן לשנות בקלות את התוכן של האוגר במהלך התוכנית, שיטת פנייה זו מאפשרת לך להקצות באופן דינמי את הכתובת של אופרנד עבור הוראת מכונה כלשהי. מאפיין זה שימושי מאוד, למשל, לארגון חישובים מחזוריים ולעבודה עם מבני נתונים שונים כגון טבלאות או מערכים.

כתובת בסיס עקיפה (אוגר) עם היסט

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

לדוגמה, ההוראה mov ax,[edx+3h] מעבירה את המילים מאזור הזיכרון ל-registers ax בכתובת: התוכן של edx + 3h.

ההוראה mov ax,mas[dx] מעבירה מילה לתוך אוגרי ה-ax בכתובת: התוכן של dx בתוספת הערך של המזהה mas (זכור שהמהדר מקצה לכל מזהה ערך השווה להיסט של מזהה זה מ- תחילת מקטע הנתונים).

כתובת אינדקס עקיפה עם היסט

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

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

לדוגמה, בהוראה mov ax,mas[si*2], הערך של הכתובת האפקטיבית של האופרנד השני מחושב על ידי הביטוי mas+(si)*2. בשל העובדה שלאסמבלר אין את האמצעים לארגן אינדקס מערך, המתכנת צריך לארגן זאת בעצמו.

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

כתובת אינדקס בסיס עקיפה

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

כתובת אינדקס בסיס עקיפה עם היסט

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

לדוגמה, ההוראה mov eax,[esi+5] [edx] מעבירה מילה כפולה ל-eax register בכתובת: (esi) + 5 + (edx).

הפקודה add ax,array[esi] [ebx] מוסיפה את התוכן של register ax לתוכן המילה בכתובת: הערך של מערך המזהה + (esi) + (ebx).

הרצאה מס' 18. צוותים

1. פקודות העברת נתונים

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

1) העברת נתונים למטרות כלליות;

2) קלט-פלט ליציאה;

3) עבודה עם כתובות ומצביעים;

4) טרנספורמציות נתונים;

5) עבודה עם הערימה.

פקודות העברת נתונים כלליות

קבוצה זו כוללת את הפקודות הבאות:

1) mov היא פקודת העברת הנתונים הבסיסית. הוא מיישם מגוון רחב של אפשרויות משלוח. שימו לב לפרטים של פקודה זו:

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

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

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

ד) אינך יכול להשתמש ב-Cs register of segment כאופרנד יעד. הסיבה פשוטה. העובדה היא שבארכיטקטורה של המיקרו-מעבד, צמד cs: ip תמיד מכיל את הכתובת של הפקודה שאמורה להתבצע לאחר מכן. שינוי התוכן של אוגר ה-CS עם הפקודה mov פירושו למעשה פעולת קפיצה, לא העברה, דבר שאינו מקובל. 2) xchg - משמש להעברת נתונים דו-כיוונית. עבור פעולה זו, כמובן, אתה יכול להשתמש ברצף של מספר הוראות mov, אך בשל העובדה שפעולת ההחלפה משמשת לעתים קרובות למדי, מפתחי מערכת הוראות המיקרו-מעבד ראו צורך להציג הוראה נפרדת לחילופי xchg. באופן טבעי, האופרנדים חייבים להיות מאותו סוג. אסור (כמו לכל הוראות ה-assembler) להחליף את התוכן של שני תאי זיכרון זה עם זה.

פקודות יציאת קלט/פלט

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

אורז. 22. תרשים מושגי של בקרת חומרת מחשב

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

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

1) ב-accumulator, port_number - קלט למצבר מהיציאה עם מספר port_number;

2) out port, accumulator - פלט את תוכן המצבר ליציאה עם המספר port_number.

פקודות לעבודה עם כתובות ומצביעי זיכרון

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

1) יעד lea, מקור - טעינת כתובת יעילה;

2) יעד מזהה, מקור - טעינת המצביע לתוך אוגר מקטע הנתונים ds;

3) les destination, source - טעינת המצביע לתוך האוגר של מקטע הנתונים הנוסף es;

4) lgs destination, source - טעינת המצביע לתוך האוגר של מקטע הנתונים הנוסף gs;

5) יעד lfs, מקור - טעינת המצביע לתוך האוגר של מקטע הנתונים הנוסף fs;

6) יעד lss, מקור - טען מצביע לתוך אוגר מקטע מחסנית ss.

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

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

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

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

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

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

פקודות המרת נתונים

ניתן לייחס הוראות מיקרו-מעבד רבות לקבוצה זו, אך לרובן יש תכונות מסוימות המחייבות את ייחוסן לקבוצות פונקציונליות אחרות. לכן, מתוך כל קבוצת הפקודות של המיקרו-מעבד, ניתן לייחס ישירות פקודה אחת לפקודות המרת נתונים: xlat [כתובת_של_טבלת_המרת קידוד]

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

המילה "טבלה" מותנית מאוד, למעשה, היא רק מחרוזת של בתים. הכתובת של הבית במחרוזת שתחליף את התוכן של אוגר al נקבעת לפי הסכום (bx) + (al), כלומר התוכן של al פועל כאינדקס במערך הביטים.

כאשר עובדים עם הפקודה xlat, שימו לב לנקודה העדינה הבאה. למרות שהפקודה מציינת את הכתובת של מחרוזת הבתים שממנה יש לאחזר את הערך החדש, כתובת זו חייבת להיטען מראש (לדוגמה, באמצעות הפקודה lea) לתוך האוגר bx. לפיכך, האופרנד lookup_table_address אינו נחוץ באמת (האופציונליות של האופרנד מוצגת על ידי הגדר אותו בסוגריים מרובעים). באשר למחרוזת הבתים (טבלת ההמרה), זהו אזור זיכרון בגודל של 1 עד 255 בתים (הטווח של מספר ללא סימן באוגר של 8 סיביות).

מחסנית פקודות

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

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

לערימה שלושה אוגרים:

1) ss - אוגר מקטע מחסנית;

2) sp/esp - אוגר מצביע מחסנית;

3) bp/ebp - אוגר מצביע בסיס מסגרת מחסנית.

גודל הערימה תלוי במצב ההפעלה של המיקרו-מעבד ומוגבל ל-64 KB (או 4 GB במצב מוגן).

רק מחסנית אחת זמינה בכל פעם, שכתובת המקטע שלה כלולה במאגר ה-SS. מחסנית זו נקראת המחסנית הנוכחית. על מנת להתייחס למחסנית אחרת ("החלף את המחסנית"), יש צורך לטעון כתובת נוספת ל-ss register. האוגר SS משמש אוטומטית על ידי המעבד כדי לבצע את כל ההוראות שעובדות על הערימה.

אנו מפרטים עוד כמה תכונות של עבודה עם הערימה:

1) כתיבה וקריאה של נתונים על המחסנית מתבצעת בהתאם לעקרון LIFO,

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

3) בעת שימוש באוגרי esp/sp ו-ebp/bp עבור כתובת זיכרון, האסמבלר מחשיב אוטומטית שהערכים הכלולים בו הם קיזוזים ביחס לאוגר המקטע ss.

באופן כללי, הערימה מאורגנת כפי שמוצג באיור 23.

אורז. 23. תרשים מושגי של ארגון מחסנית

אוגרי ה-SS, ESP/SP ו-EUR/BP נועדו לעבוד עם הערימה. רגיסטרים אלו משמשים בצורה מורכבת, ולכל אחד מהם יש מטרה פונקציונלית משלו.

פנקס ה-ESP/SP מצביע תמיד על החלק העליון של הערימה, כלומר, הוא מכיל את ההיסט שבו הרכיב האחרון נדחף אל המחסנית. הוראות המחסנית משנות באופן מרומז את האוגר הזה כך שהוא תמיד מצביע על האלמנט האחרון שנדחף אל המחסנית. אם המחסנית ריקה, אז הערך של esp שווה לכתובת של הבית האחרון של המקטע שהוקצה עבור המחסנית. כאשר אלמנט נדחף אל המחסנית, המעבד מוריד את הערך של ה-esp register, ולאחר מכן כותב את האלמנט לכתובת של הקודקוד החדש. כאשר מוציאים נתונים מהמחסנית, המעבד מעתיק את האלמנט הממוקם בכתובת הקודקוד, ולאחר מכן מגדיל את הערך של אוגר המצביע מחסנית esp. כך, מסתבר שהמחסנית גדלה למטה, לכיוון של ירידה בכתובות.

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

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

תחילת המחסנית ממוקמת בכתובות זיכרון גבוהות יותר. באיור 23, כתובת זו מסומנת בצמד ss: fffF. ההסטה של ​​wT ניתנת כאן באופן מותנה. במציאות, ערך זה נקבע לפי הערך שהמתכנת מציין בעת ​​תיאור מקטע המחסנית בתוכנית שלו.

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

1. push source - כתיבת ערך המקור לראש הערימה.

מעניין הוא האלגוריתם של פקודה זו, הכולל את הפעולות הבאות (איור 24):

1) (sp) = (sp) - 2; הערך של sp מופחת ב-2;

2) הערך מהמקור נכתב לכתובת שצוינה ב-ss: sp pair.

אורז. 24. איך פועלת פקודת הדחיפה

2. הקצאת פופ - כתיבת הערך מהחלק העליון של הערימה למיקום שצוין על ידי אופרנד היעד. לכן הערך "מוסר" מהחלק העליון של הערימה. האלגוריתם של פקודת ה-pop הוא ההפך מהאלגוריתם של פקודת הדחיפה (איור 25):

1) כתיבת תוכן החלק העליון של הערימה במיקום המצוין על ידי אופרנד היעד;

2) (sp) = (sp) + 2; הגדלת הערך של sp.

אורז. 25. איך פועלת פקודת הפופ

3. pusha - פקודת כתיבה קבוצתית לערימה. לפי פקודה זו, האוגרים ax, cx, dx, bx, sp, bp, si, di נכתבים ברצף לערימה. שימו לב שהתוכן המקורי של sp כתוב, כלומר התוכן שהיה לפני הוצאת הפקודה pusha (איור 26).

אורז. 26. איך פועלת הפקודה pusha

4. pushaw זה כמעט שם נרדף לפקודת pusha מה ההבדל? תכונת bitness יכולה להיות use16 או use32. בואו נסתכל כיצד פועלות הפקודות pusha ו-pushaw עם כל אחת מהתכונות הללו:

1) use16 - אלגוריתם pushaw דומה לאלגוריתם pusha;

2) use32 - pushaw לא משתנה (כלומר, הוא לא רגיש לרוחב המקטע ועובד תמיד עם אוגרים בגודל מילים - ax, cx, dx, bx, sp, bp, si, di). פקודת pusha רגישה לרוחב הקטע שנקבע וכאשר מצוין קטע של 32 סיביות, היא פועלת עם האוגרים המתאימים של 32 סיביות, כלומר eax, esx, edx, ebx, esp, ebp, esi, edi.

5. pushad - מבוצע בדומה לפקודה pusha, אבל יש כמה מוזרויות.

שלוש הפקודות הבאות מבצעות את ההפך מהפקודות לעיל:

1) רורה;

2) popaw;

3) פופ.

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

1. pushf - שומר את רישום הדגלים בערימה.

הפעולה של פקודה זו תלויה בתכונת גודל המקטע:

1) השתמש ב-16 - אוגר הדגלים בגודל 2 בתים נכתב לערימה;

2) use32 - אוגר ה-eflags של 4 בתים נכתב לערימה.

2. pushfw - שמירת אוגר בגודל מילה של דגלים על הערימה. תמיד עובד כמו pushf עם התכונה use16.

3. pushfd - שמירת ה-flags או eflags flags register על הערימה בהתאם לתכונת ה-bit width של הקטע (כלומר, זהה ל-pushf).

באופן דומה, שלוש הפקודות הבאות מבצעות את ההיפך מהפעולות שנדונו לעיל:

1) popf;

2) popftv;

3) popfd.

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

1) קריאה לשגרות משנה;

2) אחסון זמני של ערכי רישום;

3) הגדרה של משתנים מקומיים.

2. פקודות חשבון

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

1) מכשיר לביצוע פעולות שלמים;

2) מכשיר לביצוע פעולות נקודה צפה.

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

סקירה של קבוצת הוראות ונתונים חשבוניות

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

אורז. 27. סיווג פקודות חשבון

קבוצת ההוראות האריתמטיות של מספרים שלמים פועלת עם שני סוגים של מספרים:

1) מספרים בינאריים שלמים. מספרים עשויים להיות בעלי ספרה חתומה או לא, כלומר, להיות מספרים חתומים או לא חתומים;

2) מספרים עשרוניים שלמים.

שקול את הפורמטים של המכונה שבהם מאוחסנים סוגי נתונים אלה.

מספרים בינאריים שלמים

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

המימד של מספר שלם בינארי יכול להיות 8, 16 או 32 סיביות. הסימן של מספר בינארי נקבע לפי האופן שבו מתפרש הסיבית המשמעותית ביותר בייצוג המספר. זהו סיביות 7,15 או 31 עבור מספרים של הממד המתאים. יחד עם זאת, מעניין שבין פקודות החשבון יש רק שתי פקודות שבאמת לוקחות בחשבון את הביט המשמעותי ביותר הזה כסימן אחד, אלו הן פקודות הכפל והחילוק השלם imul ו-idiv. במקרים אחרים, האחריות לפעולות עם מספרים חתומים ובהתאם גם עם סיבית סימן מוטלת על המתכנת. טווח הערכים של מספר בינארי תלוי בגודלו ובפירושו של הסיבית המשמעותית ביותר או כסיבית המשמעותית ביותר של המספר או כסיבית הסימן של המספר (טבלה 9).

טבלה 9. טווח של מספרים בינאריים מספרים עשרוניים

מספרים עשרוניים הם סוג מיוחד של ייצוג מידע מספרי, המבוסס על העיקרון של קידוד כל ספרה עשרונית של מספר בקבוצה של ארבע סיביות. במקרה זה, כל בייט של המספר מכיל ספרה עשרונית אחת או שתיים במה שנקרא קוד עשרוני מקודד בינארי (BCD - Binary-Coded Decimal). המיקרו-מעבד מאחסן מספרי BCD בשני פורמטים (איור 28):

1) פורמט ארוז. בפורמט זה, כל בייט מכיל שתי ספרות עשרוניות. ספרה עשרונית היא ערך בינארי של 0 סיביות בין 9 ל-4. במקרה זה, הקוד של הספרה הגבוהה ביותר של המספר תופס את 4 הסיביות הגבוהות ביותר. לכן, טווח הייצוג של מספר עשרוני ארוז ב-1 בתים הוא מ-00 עד 99;

2) פורמט לא ארוז. בפורמט זה, כל בייט מכיל ספרה עשרונית אחת בארבעת הביטים הפחות משמעותיים. 4 הסיביות העליונות מוגדרות לאפס. זה מה שנקרא אזור. לכן, הטווח של ייצוג מספר עשרוני לא ארוז ב-1 בתים הוא מ-0 עד 9.

אורז. 28. ייצוג מספרי BCD

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

פעולות אריתמטיות על מספרים שלמים בינאריים

הוספת מספרים בינאריים ללא סימנים

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

לדוגמה, בוא נעשה את החיבור: 254 + 5 = 259 בבינארי. 11111110 + 0000101 = 1 00000011. התוצאה חרגה מ-8 סיביות והערך הנכון שלה מתאים ל-9 סיביות, והערך 8 נשאר בשדה 3 הסיביות של האופרנד, מה שכמובן אינו נכון. במיקרו-מעבד חזו תוצאה זו של התוספת וניתנים אמצעים מיוחדים לתיקון מצבים כאלה ולעיבודם. לכן, כדי לתקן את המצב של מעבר לרשת הסיביות של התוצאה, כמו במקרה זה, נועד דגל ה-carry cf. הוא ממוקם בסיביות 0 של אוגר הדגל EFLAGS/FLAGS. ההגדרה של הדגל הזה היא שמקבעת את עובדת ההעברה של אחד מהמסדר הגבוה של האופרנד. מטבע הדברים, על המתכנת לקחת בחשבון את האפשרות של תוצאה כזו של פעולת ההוספה ולספק אמצעים לתיקון. זה כולל הכללת קטעי קוד לאחר פעולת ההוספה שבה מנותח דגל cf. ניתן לנתח דגל זה בדרכים שונות.

הקל והנגיש ביותר הוא להשתמש בפקודת הענף המותנה jcc. להוראה זו יש כאופרנד את שם התווית בקטע הקוד הנוכחי. המעבר לתווית זו מתבצע אם כתוצאה מפעולת הפקודה הקודמת, דגל cf מוגדר ל-1. במערכת הפקודות המיקרו-מעבד קיימות שלוש פקודות תוספת בינאריות:

1) אופרנד inc - פעולת הגדלה, כלומר הגדל את הערך של האופרנד ב-1;

2) הוסף אופרנד_1, אופרנד_2 - הוראת חיבור עם עקרון הפעולה: operand_1 = operand_1 + operand_2;

3) adc operand_1, operand_2 - הוראת הוספה תוך התחשבות בדגל הנשיאה cf. עקרון פעולת הפקודה: operand_1 = operand_1 + operand_2 + value_sG.

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

תוספת בינארית חתומה

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

1) דגל ה-cf carry, הגדרתו ל-1 מציינת שהאופרנדים היו מחוץ לטווח;

2) פקודת adc, שלוקחת בחשבון אפשרות של יציאה כזו (carry מהביט הפחות משמעותי).

אמצעי נוסף הוא לרשום את מצב הסיביות מסדר גבוה (סימן) של האופרנד, אשר נעשה באמצעות דגל הגלישה של באוגר EFLAGS (סיביות 11).

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

דוגמה

30566 = 0111011101100110

+

00687 = 00000010

=

31253 = 01111010

אנו עוקבים אחר ההעברות מהספרות ה-14 וה-15 ונכונות התוצאה: אין העברות, התוצאה נכונה.

דוגמה

30566 = 0111011101100110

+

30566 = 0111011101100110

=

1132 = 11101110

הייתה העברה מהקטגוריה ה-14; אין העברה מהקטגוריה ה-15. התוצאה שגויה, כי יש הצפה - הערך של המספר התברר כגדול ממה שיכול להיות למספר חתום של 16 סיביות (+32 767).

דוגמה

-30566 = 10001000 10011010

+

-04875 = 11101100 11110101

=

-35441 = 01110101 10001111

הייתה העברה מהספרה ה-15, אין העברה מהספרה ה-14. התוצאה לא נכונה, כי במקום מספר שלילי, הוא התברר כחיובי (הביט המשמעותי ביותר הוא 0).

דוגמה

-4875 = 11101100 11110101

+

-4875 = 11101100 11110101

=

09750 = 11011001

יש העברות מהסיביות ה-14 וה-15. התוצאה נכונה.

לפיכך, בדקנו את כל המקרים וגילינו שמצב ההצפה (הגדרת דגל OF ל-1) מתרחש במהלך ההעברה:

1) מהספרה ה-14 (עבור מספרים חיוביים חתומים);

2) מהספרה ה-15 (עבור מספרים שליליים).

לעומת זאת, לא מתרחשת הצפה (כלומר, דגל ה-OF מאופס ל-0) אם יש שידור משני הסיביות או אם אין שידור בשני הסיביות.

אז overflow נרשם עם דגל ההצפה של. בנוסף לדגל של, בעת העברה מהסיביות מסדר גבוה, דגל ההעברה CF מוגדר ל-1. מאחר שהמיקרו-מעבד אינו יודע על קיומם של מספרים חתומים וחסרי סימן, המתכנת הוא האחראי הבלעדי לפעולות הנכונות עם המספרים המתקבלים. אתה יכול לנתח את דגלי ה-CF וה-OF עם הוראות הקפיצה המותנית JC\JNC ו-JO\JNO, בהתאמה.

לגבי הפקודות להוספת מספרים עם סימן, הן זהות למספרים ללא סימן.

חיסור של מספרים בינאריים ללא סימן

כמו בניתוח פעולת החיבור, נדון במהות התהליכים המתרחשים בעת ביצוע פעולת החיסור. אם ה-minuend גדול מה-subtrahend, אז אין בעיה - ההבדל הוא חיובי, התוצאה נכונה. אם המינואנד קטן מהחסר, יש בעיה: התוצאה קטנה מ-0, וזה כבר מספר בסימן. במקרה זה, התוצאה חייבת להיות עטופה. מה זה אומר? בחיסור הרגיל (בעמודה), הם נותנים הלוואה של 1 מהסדר הגבוה ביותר. המיקרו-מעבד עושה את אותו הדבר, כלומר, הוא לוקח 1 מהספרה העוקבת אחרי הגבוהה ביותר ברשת הסיביות של האופרנד. בואו נסביר עם דוגמה.

דוגמה

05 = 00000000

-10 = 00000000 00001010

כדי לבצע את החיסור, בוא נעשה

הלוואה דמיונית בכירה:

100000000 00000101

-

00000000 00001010

=

11111111 11111011

כך, בעצם, הפעולה

(65 + 536) - 5 = 10

0 כאן הוא, כביכול, שווה ערך למספר 65536. התוצאה, כמובן, שגויה, אבל המיקרו-מעבד חושב שהכל בסדר, למרות שהוא מתקן את העובדה של השאלת יחידה על ידי הגדרת דגל ה-carrier cf. אבל הסתכל שוב היטב על התוצאה של פעולת החיסור. זה המשלים של -5 בשניים! נערוך ניסוי: נציג את ההפרש כסכום של 5 + (-10).

דוגמה

5 = 00000000

+

(-10)= 11111111 11110110

=

11111111 11111011

כלומר קיבלנו את אותה תוצאה כמו בדוגמה הקודמת.

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

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

1) dec operand - פעולת הקטנה, כלומר הקטנת ערך האופרנד ב-1;

2) sub operand_1, operand_2 - פקודת חיסור; עקרון הפעולה שלו: operand_1 = operand_1 - operand_2;

3) sbb operand_1, operand_2 - פקודת חיסור תוך התחשבות בהלוואה (דגל ci): operand_1 = operand_1 - operand_2 - value_sG.

כפי שניתן לראות, בין פקודות החיסור ישנה פקודת sbb שלוקחת בחשבון את דגל ה- carry cf. פקודה זו דומה ל-adc, אך כעת דגל cf פועל כאינדיקטור להשאלת 1 מהספרה המשמעותית ביותר בעת הפחתת מספרים.

חיסור בינארי חתום

כאן הכל קצת יותר מסובך. המיקרו-מעבד לא צריך שני מכשירים - חיבור וחיסור. מספיק שיהיה רק ​​אחד - מכשיר התוספת. אבל בשביל חיסור בדרך של הוספת מספרים עם סימן בקוד נוסף, יש צורך לייצג את שני האופרנדים - גם את המופחת וגם את המופחת. יש להתייחס לתוצאה גם כערך משלים של שני. אבל כאן מתעוררים קשיים. קודם כל, הם קשורים לעובדה שהחלק המשמעותי ביותר של האופרנד נחשב כסיבית סימן. שקול את הדוגמה של חיסור 45 - (-127).

דוגמה

חיסור של מספרים חתומים 1

45 = 0010

-

-127 = 1000 0001

=

-44 = 1010 1100

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

דוגמה

חיסור של מספרים חתומים 2

-45-45 = -45 + (-45) = -90.

-45 = 11010011

+

-45 = 11010011

=

-90 = 1010 0110

הכל בסדר כאן, דגל הגלישה של מאופס ל-0, ו-1 בסיבית הסימן מציין שערך התוצאה הוא מספר משלים של שתיים.

חיסור וחיבור של אופרנדים גדולים

אם תשים לב, הוראות החיבור והחיסור פועלות עם אופרנדים של ממד קבוע: 8, 16, 32 סיביות. אבל מה אם אתה צריך להוסיף מספרים בממד גדול יותר, למשל 48 סיביות, באמצעות אופרנדים של 16 סיביות? לדוגמה, בואו נוסיף שני מספרים של 48 סיביות:

אורז. 29. הוספת אופרנדים גדולים

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

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

לסיום הדיון שלנו בהוראות החיבור והחיסור, בנוסף ל-cf ושל דגלים, ישנם עוד כמה דגלים בפנקס ה-eflags שניתן להשתמש בהם עם הוראות חשבון בינאריות. אלו הדגלים הבאים:

1) zf - דגל אפס, המוגדר ל-1 אם תוצאת הפעולה היא 0, ול-1 אם התוצאה אינה שווה ל-0;

2) sf - דגל סימן, שערכו לאחר פעולות אריתמטיות (ולא רק) עולה בקנה אחד עם הערך של הביט המשמעותי ביותר של התוצאה, כלומר עם סיביות 7, 15 או 31. לפיכך, ניתן להשתמש בדגל זה לפעולות על מספרים חתומים.

כפל של מספרים ללא סימנים

הפקודה להכפלת מספרים ללא סימנים היא

mul factor_1

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

טבלה 10. סידור האופרנדים והתוצאה לכפל

ניתן לראות מהטבלה שהמוצר מורכב משני חלקים ובהתאם לגודל האופרנדים הוא ממוקם בשני מקומות - במקום factor_2 (חלק תחתון) ובאוגר הנוסף ah, dx, edx (גבוהה יותר) חֵלֶק). כיצד, אם כן, באופן דינמי (כלומר, במהלך ביצוע התוכנית) לדעת שהתוצאה קטנה מספיק כדי להתאים לרישום אחד, או שהיא חרגה מהממד של הרגיסטר והחלק הגבוה ביותר הגיע למאגר אחר? לשם כך, אנו משתמשים בדגלי cf ו-overflow שכבר ידועים לנו מהדיון הקודם:

1) אם החלק המוביל של התוצאה הוא אפס, אז לאחר פעולת המוצר הדגלים cf = 0 ושל = 0;

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

הכפל מספרים בסימנים

הפקודה להכפלת מספרים בסימן היא

[imul operand_1, operand_2, operand_3]

פקודה זו מבוצעת באותו אופן כמו פקודת mul. מאפיין ייחודי של פקודת imul הוא רק היווצרות השלט.

אם התוצאה קטנה ומתאימה לרישום אחד (כלומר, אם cf = של = 0), אז התוכן של האוגר השני (החלק הגבוה) הוא הרחבת סימן - כל הביטים שלו שווים לביט הגבוה (סיביות סימן ) של החלק הנמוך של התוצאה. אחרת (אם cf = של = 1), הסימן של התוצאה הוא סיביות הסימן של החלק הגבוה של התוצאה, וסיבית הסימן של החלק הנמוך הוא הסיבית המשמעותית של קוד התוצאה הבינארי.

חלוקה של מספרים לא חתומים

הפקודה לחלוקת מספרים ללא סימנים היא

מחלק div

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

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

טבלה 11. סידור האופרנדים והתוצאה בחלוקה

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

1) המחלק הוא אפס;

2) המנה לא נכללת ברשת הסיביות שהוקצתה עבורה, מה שיכול לקרות במקרים הבאים:

א) כאשר מחלקים דיבידנד בערך של מילה במחלק בעל ערך בתים, וערך הדיבידנד גדול פי 256 משווי המחלק;

ב) כאשר מחלקים דיבידנד בערך של מילה כפולה במחלק בעל ערך של מילה, וערך הדיבידנד גדול פי 65 משווי המחלק;

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

חלוקה עם שלט

הפקודה לחלוקת מספרים בסימן היא

מחלק idiv

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

1) המחלק הוא אפס;

2) המנה לא נכללת ברשת הסיביות שהוקצתה עבורה.

האחרון בתורו יכול לקרות:

1) כאשר מחלקים דיבידנד עם ערך מילה בסימן במחלק עם ערך בתים חתום, וערך הדיבידנד הוא יותר מ-128 פעמים מערכו של המחלק (לפיכך, המנה לא צריכה להיות מחוץ לטווח שבין -128 ל + 127);

2) כאשר מחלקים את הדיבידנד בערך מילה כפולה חתומה על ידי המחלק בערך מילה חתומה, וערך הדיבידנד הוא יותר מפי 32 מערך המחלק (לפיכך, המנה לא חייבת להיות מחוץ לטווח שבין - 768 עד +32);

3) כאשר מחלקים את הדיבידנד בערך מרובע מילים חתום במחלק מילים כפול חתום, וערך הדיבידנד הוא יותר מפי 2 מערכו של המחלק (לפיכך, המנה לא חייבת להיות מחוץ לטווח של -147 עד + 483 648 2 147).

הוראות עזר לפעולות מספר שלם

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

הקלד פקודות המרה

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

ישנם שני סוגים של פקודות המרת סוג.

1. הוראות ללא אופרנדים. פקודות אלה פועלות עם אוגרים קבועים:

1) cbw (Convert Byte to Word) - פקודה להמרת בייט (ב-al register) למילה (ב-ah register) על ידי הפצת הערך של bit high al לכל הסיביות של אוגר ah;

2) cwd (המר מילה לכפול) - פקודה להמרת מילה (ב-register ax) למילה כפולה (ב-registers dx: ax) על-ידי הפצת הערך של אקס הסיביות הגבוה לכל הסיביות של האוגר dx;

3) cwde (המר מילה לכפולה) - פקודה להמרת מילה (ב-register ax) למילה כפולה (ב-register eax) על-ידי הפצת הערך של גרזן הביט הגבוה לכל הביטים של החצי העליון של אוגר ה-eax. ;

4) cdq (Convert Double Word to Quarter Word) - פקודה להמרת מילה כפולה (באוגר ה-eax) למילה מרובעת (ב-edx: eax registers) על ידי הפצת הערך של ה-bit המשמעותי ביותר של eax לכולם סיביות של האוגר edx.

2. פקודות movsx ו-movzx הקשורות לפקודות עיבוד מחרוזות. לפקודות האלה יש תכונה שימושית בהקשר של הבעיה שלנו:

1) movsx operand_1, operand_2 - שלח עם הפצת סימן. מרחיב ערך של 8 או 16 סיביות של אופרנד_2, שיכול להיות אופרנד או אופרנד זיכרון, לערך של 16 או 32 סיביות באחד הרגיסטרים, תוך שימוש בערך סיביות הסימן כדי למלא את המיקומים הגבוהים יותר של אופרנד_1. הוראה זו שימושית להכנת אופרנדים חתומים לפעולות אריתמטיות;

2) movzx operand_1, operand_2 - שלח עם אפס סיומת. מרחיב את הערך של 8-bit או 16-bit של operand_2 ל-16-bit או 32-bit, מנקה (מילוי) את המיקומים הגבוהים של operand_2 באפסים. הוראה זו שימושית להכנת אופרנדים ללא סימנים עבור חשבון.

פקודות שימושיות אחרות

1. xadd יעד, מקור - החלפה והוספה.

הפקודה מאפשרת לך לבצע שתי פעולות ברצף:

1) החלפת ערכי יעד ומקור;

2) הצב את אופרנד היעד במקום הסכום: יעד = יעד + מקור.

2. אופרנד neg - שלילה עם משלים של שניים.

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

אופרנד = 0 - אופרנד, כלומר מפחית את האופרנד מאפס.

ניתן להשתמש בפקודת האופרנד neg:

1) לשנות את השלט;

2) לבצע חיסור מקבוע.

פעולות אריתמטיות על מספרים בינאריים-עשרוניים

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

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

1) לערכים בפורמט מילה ומילה כפולה יש טווח מוגבל. אם התוכנית מיועדת לעבוד בתחום הפיננסים, אז הגבלת הסכום ברובל ל-65 (למילה) או אפילו 536 (עבור מילה כפולה) תצמצם משמעותית את היקף היישום שלה;

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

3) הצגת כמות גדולה של תוצאות בצורה סמלית (קוד ASCII). תוכניות עסקיות לא עושות רק חישובים; אחת ממטרות השימוש בהם היא מסירה מהירה של מידע למשתמש. לשם כך, כמובן, יש להציג את המידע בצורה סמלית. המרת מספרים מבינארי ל-ASCII דורשת מאמץ חישובי מסוים. מספר נקודה צפה קשה עוד יותר לתרגום לצורה סמלית. אבל אם תסתכל על הייצוג ההקסדצימלי של ספרה עשרונית לא ארוז והתו התואם שלה בטבלת ASCII, אתה יכול לראות שהם שונים ב-30 שעות. לפיכך, ההמרה לצורה סמלית ולהיפך היא הרבה יותר קלה ומהירה.

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

אריתמטיקה על מספרי BCD לא ארוזים

הוסף מספרי BCD לא ארוזים

הבה נבחן שני מקרים של הוספה.

דוגמה

תוצאת ההוספה היא לא יותר מ-9

6 = 0000

+

3 = 0000

=

9 = 0000

אין העברה מהטטראד הזוטר לבוגר. התוצאה נכונה.

דוגמה

תוצאת ההוספה גדולה מ-9:

06 = 0000

+

07 = 0000

=

13 = 0000

לא קיבלנו עוד מספר BCD. התוצאה שגויה. התוצאה הנכונה בפורמט BCD לא ארוז צריכה להיות 0000 0001 0000 0011 בבינארי (או 13 בעשרוני).

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

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

במקרה של חיסור בדוגמה 10, ניתן לראות שיש לתקן את התוצאה המתקבלת. כדי לתקן את פעולת הוספת שני מספרי BCD לא ארוזים חד-ספרתיים במערכת הפיקוד של המיקרו-מעבד, קיימת פקודה מיוחדת - aaa (ASCII Adjust for Addition) - תיקון תוצאת החיבור לייצוג בצורה סמלית.

להוראה זו אין אופרנדים. זה עובד באופן מרומז רק עם ה-al register ומנתח את הערך של הטטרד התחתון שלו:

1) אם ערך זה קטן מ-9, הדגל cf מאופס ל-XNUMX והמעבר להוראה הבאה מתבצע;

2) אם ערך זה גדול מ-9, הפעולות הבאות מבוצעות:

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

ב) הדגל cf מוגדר ל-1, ובכך מקבע את ההעברה לביט המשמעותי ביותר כך שניתן יהיה לקחת אותו בחשבון בפעולות הבאות.

אז, בדוגמה 10, בהנחה שערך הסכום 0000 1101 נמצא ב-al, לאחר הוראת aaa, לרשום יהיה 1101 + 0110 = 0011, כלומר בינארי 0000 0011 או עשרוני 3, ודגל cf יוגדר ל-1, כלומר, ההעברה נשמרה במיקרו-מעבד. בשלב הבא, המתכנת יצטרך להשתמש בהוראה להוספת adc, שתיקח בחשבון את ה-carry מהסיביות הקודמת.

חיסור של מספרי BCD לא ארוזים

המצב כאן די דומה לתוספת. בואו נשקול את אותם מקרים.

דוגמה

תוצאת החיסור אינה גדולה מ-9:

6 = 0000

-

3 = 0000

=

3 = 0000

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

דוגמה

תוצאת החיסור גדולה מ-9:

6 = 0000

-

7 = 0000

=

-1 = 1111 1111

החיסור מתבצע על פי כללי החשבון הבינארי. לכן, התוצאה אינה מספר BCD.

התוצאה הנכונה בפורמט BCD לא ארוז צריכה להיות 9 (0000 1001 בבינארי). במקרה זה, מניחים שאילה מהספרה המשמעותית ביותר, כמו בפקודת חיסור רגילה, כלומר במקרה של מספרי BCD, למעשה יש לבצע חיסור של 16 - 7. לפיכך, ברור שכמו ב- במקרה של חיבור, יש לתקן את תוצאת החיסור. לשם כך ישנה פקודה מיוחדת - aas (ASCII Adjust for Substraction) - תיקון תוצאת החיסור לייצוג בצורה סמלית.

גם להוראת aas אין אופרנדים והיא פועלת על ה-al register, ומנתחת את הטטרד מסדר המינימום שלו באופן הבא:

1) אם הערך שלו קטן מ-9, אז הדגל cf מאופס ל-0 והשליטה מועברת לפקודה הבאה;

2) אם ערך ה-tetrad ב-al גדול מ-9, הפקודה aas מבצעת את הפעולות הבאות:

א) גורע 6 מתוכן הטטרד התחתון של רגיסטר al (שימו לב - לא מתוכן הרגיסטר כולו);

ב) מאפס את הטטרד העליון של registr al;

ג) מציב את דגל cf ל-1, ובכך מתקן את ההשאלה הדמיונית מסדר גבוה.

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

הכפלה של מספרי BCD לא ארוזים

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

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

על מנת להכפיל מספרים של מימד שרירותי, עליך ליישם את תהליך הכפל בעצמך, בהתבסס על אלגוריתם כפל כלשהו, ​​למשל, "בעמודה".

על מנת להכפיל שני מספרי BCD חד ספרתיים, עליך:

1) הצב את אחד הגורמים בפנקס ה-AL (כנדרש בהוראת מול);

2) הצב את האופרנד השני באוגר או בזיכרון, הקצאת בתים;

3) הכפל את הגורמים בפקודת mul (התוצאה, כצפוי, תהיה ב-ah);

4) התוצאה, כמובן, תהיה בקוד בינארי, ולכן יש לתקן אותה.

לתיקון התוצאה לאחר הכפל, נעשה שימוש בפקודה מיוחדת - aam (ASCII Adjust for Multiplication) - תיקון תוצאת הכפל לייצוג בצורה סמלית.

אין לו אופרנדים והוא פועל על רישום ה-AX באופן הבא:

1) מחלק את אל ב-10;

2) תוצאת החלוקה נכתבת כך: מנה ב-al, שארית ב-ah. כתוצאה מכך, לאחר ביצוע הוראת aam, אוגרי AL ו-ah מכילים את ספרות ה-BCD הנכונות של המכפלה של שתי ספרות.

לפני שנסיים את הדיון בפקודה aam, עלינו לציין שימוש נוסף בה. ניתן להשתמש בפקודה זו כדי להמיר מספר בינארי באוגר AL למספר BCD לא ארוז, שיוצב באוגר ah: הספרה המשמעותית ביותר של התוצאה היא ב-ah, הספרה הפחות משמעותית היא ב-al. ברור שהמספר הבינארי חייב להיות בטווח 0...99.

חלוקה של מספרי BCD לא ארוזים

תהליך ביצוע פעולת החלוקה של שני מספרי BCD לא ארוזים שונה במקצת משאר הפעולות שנחשבו קודם לכן איתם. גם כאן נדרשות פעולות תיקון, אך יש לבצע אותן לפני הפעולה הראשית המחלקה ישירות מספר BCD אחד במספר BCD אחר. ראשית, ברישום אה, אתה צריך לקבל שתי ספרות BCD לא ארוזות של הדיבידנד. זה הופך את המתכנת נוח לו במובן מסוים. לאחר מכן, עליך להוציא את הפקודה aad - aad (ASCII Adjust for Division) - תיקון חלוקה לייצוג סמלי.

להוראה אין אופרנדים והיא ממירה את מספר ה-BCD הלא-ארוז הדו-ספרתי באוגר הגרזן למספר בינארי. מספר בינארי זה ישחק לאחר מכן את תפקיד הדיבידנד בפעולת החלוקה. בנוסף להמרה, פקודת aad ממקמת את המספר הבינארי המתקבל במאגר AL. הדיבידנד יהיה באופן טבעי מספר בינארי מהטווח 0...99.

האלגוריתם שבאמצעותו פקודת aad מבצעת המרה זו הוא כדלקמן:

1) הכפל את הספרה הגבוהה ביותר של מספר ה-BCD המקורי ב-ah (התוכן של AH) ב-10;

2) בצע את התוספת AH + AL, שתוצאתה (מספר בינארי) מוזנת ב-AL;

3) אפס את התוכן של AH.

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

בדומה ל-aash, ניתן להשתמש בפקודת aad גם להמרת מספרי BCD לא ארוזים מהטווח 0...99 למקבילה הבינארית שלהם.

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

אריתמטיקה על מספרי BCD ארוזים

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

הוספת מספרי BCD ארוזים

ראשית, בואו ניגש ללב הבעיה וננסה להוסיף שני מספרי BCD ארוזים דו ספרתיים. דוגמה להוספת מספרי BCD ארוזים:

67 = 01100111

+

75 = 01110101

=

142 = 1101 1100 = 220

כפי שאתה יכול לראות, בבינארי התוצאה היא 1101 1100 (או 220 בעשרוני), וזה לא נכון. הסיבה לכך היא שהמיקרו-מעבד לא מודע לקיומם של מספרי BCD ומוסיף אותם לפי הכללים להוספת מספרים בינאריים. למעשה, התוצאה ב-BCD צריכה להיות 0001 0100 0010 (או 142 בעשרוניות).

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

המיקרו-מעבד מספק לפקודה זו daa - daa (התאמה עשרונית לחיבור) - תיקון תוצאת החיבור להצגה בצורה עשרונית.

הפקודה daa ממירה את התוכן של אוגר al לשתי ספרות עשרוניות ארוזות לפי האלגוריתם שניתן בתיאור הפקודה daa. היחידה המתקבלת (אם תוצאת התוספת גדולה מ-99) נשמרת בדגל cf, ובכך לוקחים בחשבון את ההעברה לחלק המשמעותי ביותר.

חיסור של מספרי BCD ארוזים

בדומה לתוספת, המיקרו-מעבד מתייחס למספרי BCD הארוזים כבינאריים ומחסיר את מספרי BCD כבינאריים בהתאם.

דוגמה

חיסור של מספרי BCD ארוזים.

בוא נחסר 67-75. מכיוון שהמיקרו-מעבד מבצע חיסור בדרך של חיבור, נפעל לפי זה:

67 = 01100111

+

-75 = 10110101

=

-8 = 0001 1100 = 28

כפי שאתה יכול לראות, התוצאה היא 28 בעשרוניות, וזה אבסורד. ב-BCD, התוצאה צריכה להיות 0000 1000 (או 8 בעשרוניות).

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

החיסור של מספרי BCD עצמו מתבצע על ידי פקודת תת או sbb חיסור פשוטה. תיקון התוצאה מתבצע על ידי הפקודה das - das (התאמת עשרונית לחסר) - תיקון תוצאת החיסור לייצוג בצורה עשרונית.

הפקודה das ממירה את התוכן של אוגר AL לשתי ספרות עשרוניות ארוזות לפי האלגוריתם שניתן בתיאור פקודת das.

הרצאה מס' 19. פקודות העברת בקרה

1. פקודות לוגיות

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

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

אורז. 29. אמצעים לעיבוד נתונים לוגי

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

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

נתונים בוליאניים

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

חשבון ההצעה הוא קבוצה של כללים המשמשים לקביעת האמת או השקר של שילוב כלשהו של הצעות.

חשבון ההצעה משולב בצורה הרמונית מאוד עם עקרונות המחשב והשיטות הבסיסיות לתכנות שלו. כל רכיבי החומרה של המחשב בנויים על שבבי לוגיקה. המערכת לייצוג מידע במחשב ברמה הנמוכה ביותר מבוססת על הרעיון של bit. קצת, שיש רק שני מצבים (0 (שקר) ו-1 (נכון)), מתאים באופן טבעי לחשבון ההצעה.

על פי התיאוריה, ניתן לבצע את הפעולות הלוגיות הבאות על הצהרות (על ביטים).

1. שלילה (לוגית NOT) - פעולה לוגית על אופרנד אחד, שתוצאתה היא ההדדיות של הערך של האופרנד המקורי.

פעולה זו מאופיינת באופן ייחודי בטבלת האמת הבאה (טבלה 12).

טבלה 12. טבלת אמת לשלילה לוגית

2. תוספת לוגית (לוגית כולל OR) - פעולה לוגית על שני אופרנדים, שתוצאתה היא "אמת" (1) אם אחד האופרנדים או שניהם אמת (1), ו"שקר" (0) אם שני האופרנדים הם שקר (0).

פעולה זו מתוארת באמצעות טבלת האמת הבאה (טבלה 13).

טבלה 13. טבלת אמת ל-OR כולל לוגי

3. כפל לוגי (ולוגי AND) - פעולה לוגית על שני אופרנדים, שתוצאתה נכונה (1) רק אם שני האופרנדים נכונים (1). בכל שאר המקרים, ערך הפעולה הוא "שקר" (0).

פעולה זו מתוארת באמצעות טבלת האמת הבאה (טבלה 14).

טבלה 14. טבלת היגיון ואמיתות

4. תוספת בלעדית לוגית (לוגית בלעדית OR) - פעולה לוגית על שני אופרנדים, שתוצאתה היא "אמת" (1), אם רק אחד משני האופרנדים נכון (1), ושקר (0), אם שני האופרנדים הם או שקר (0) או נכון (1). פעולה זו מתוארת באמצעות טבלת האמת הבאה (טבלה 15).

טבלה 15. טבלת אמת ל-XOR לוגי

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

פקודות לוגיות

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

1) ואופרנד_1, אופרנד_2 - פעולת כפל לוגי. הפקודה מבצעת פעולת AND לוגית (צירוף) בסיביות על הסיביות של האופרנדים operand_1 ו- operand_2. התוצאה כתובה במקום operand_1;

2) og operand_1, operand_2 - פעולת הוספה לוגית. הפקודה מבצעת פעולת OR לוגית (ניתוק) בסיביות על הסיביות של האופרנדים operand_1 ו- operand_2. התוצאה כתובה במקום operand_1;

3) xor operand_1, operand_2 - פעולה של תוספת לוגית בלעדית. הפקודה מבצעת פעולת XOR לוגית בצורה סיבית על הביטים של האופרנדים operand_1 ו- operand_2. התוצאה נכתבת במקום האופרנד;

4) test operand_1, operand_2 - פעולת "בדיקה" (באמצעות שיטת הכפל הלוגי). הפקודה מבצעת פעולת AND לוגית סיבית על הביטים של האופרנדים operand_1 ו- operand_2. מצב האופרנדים נשאר זהה, רק הדגלים zf, sf ו-pf משתנים, מה שמאפשר לנתח את המצב של סיביות בודדות של האופרנד מבלי לשנות את מצבם;

5) לא אופרנד - פעולת שלילה לוגית. הפקודה מבצעת היפוך סיביות (מחליף את הערך בהפוך) של כל סיביות של האופרנד. התוצאה נכתבת במקום האופרנד.

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

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

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

1) כדי להגדיר ספרות מסוימות (סיביות) ל-1, נעשה שימוש בפקודה og operand_1, operand_2.

בהוראה זו, operand_2, הפועל כמסיכה, חייב להכיל 1 סיביות במקום אותם סיביות שיש להגדיר ל-1 ב- operand_XNUMX;

2) כדי לאפס ספרות מסוימות (סיביות) ל-0, נעשה שימוש בפקודה ובאופרנד_1, אופרנד_2.

בהוראה זו, operand_2, הפועל כמסיכה, חייב להכיל אפס ביטים במקום אותם ביטים שיש להגדיר ל-0 ב-operand_1;

3) הפקודה xor operand_1, operand_2 מוחלת:

א) כדי לגלות אילו סיביות באופרנד_1 ובאופרנד נבדלים זה מזה;

ב) כדי להפוך את המצב של הסיביות שצוינו באופרנד_1.

קטעי המסכה שמעניינים אותנו (operand_2) בעת ביצוע פקודת xor חייבים להיות בודדים, השאר חייב להיות אפס;

בדיקת הפקודה operand_1, operand_2 (check operand_1) משמשת לבדיקת המצב של הסיביות שצוינו.

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

1) אם zf = 0, אז כתוצאה מכפל לוגי, מתקבלת תוצאת אפס, כלומר סיבית יחידה אחת של המסכה, שלא תאמה לסיבית היחידה המקבילה של האופרנד;

2) אם zf = 1, אז כתוצאה מכפל לוגי, מתקבלת תוצאה שאינה אפס, כלומר, לפחות סיביות יחידה אחת של המסכה חופפת לסיבית היחידה המקבילה של operand_1.

כדי להגיב לתוצאה של פקודת הבדיקה, רצוי להשתמש בפקודה jump jnz תווית (Jump if Not Zero) - jump אם דגל האפס zf אינו אפס, או בפקודת הפעולה ההפוכה - jz label (Jump if Zero ) - קפוץ אם דגל האפס zf = 0.

שתי הפקודות הבאות מחפשות את סיבית האופרנד הראשונה שהוגדרה ל-1. ניתן לבצע את החיפוש הן מההתחלה והן מהסוף של האופרנד:

1) bsf operand_1, operand_2 (Bit Scanning Forward) - סורק ביטים קדימה. ההוראה מחפשת (סורקת) את הסיביות של operand_2 מהפחות משמעותי למשמעותי ביותר (מבית 0 עד לביט המשמעותי ביותר) בחיפוש אחר הסיביות הראשונה שהוגדרה ל-1. אם נמצא אחד, אופרנד_1 מתמלא במספר של הביט הזה כערך מספר שלם. אם כל הסיביות של אופרנד_2 הן 0, אז דגל האפס zf מוגדר ל-1, אחרת דגל zf מאופס ל-0;

2) bsr operand_1, operand_2 (Bit Scanning Reset) - סרוק סיביות בסדר הפוך. ההוראה מחפשת (סורקת) את הסיביות של operand_2 מהמשמעותית ביותר לפחות משמעותית (מהסיבית המשמעותית ביותר לביט 0) בחיפוש אחר הסיביות הראשונה שהוגדרה ל-1. אם נמצא אחד, אופרנד_1 מתמלא במספר של הביט הזה כערך מספר שלם. חשוב שהמיקום של סיבית היחידה הראשונה משמאל עדיין ייספר ביחס לביט 0. אם כל הסיביות של operand_2 הן 0, אז דגל האפס zf מוגדר ל-1, אחרת דגל zf מאופס ל-0.

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

1) אופרנד bt, bit_offset (Bit Test) - מבחן סיביות. ההוראה מעבירה את ערך הסיביות לדגל cf;

2) אופרנד bts, offset_bit (Bit Test and Set) - בדיקה והגדרת ביט. ההוראה מעבירה את ערך הסיביות לדגל ה-CF ולאחר מכן מגדירה את הביט לבדיקה ל-1;

3) btr operand, bit_offset (Bit Test and Reset) - בודק ומאפס מעט. ההוראה מעבירה את ערך הסיביות לדגל ה-CF ולאחר מכן מגדירה את הביט הזה ל-0;

4) אופרנד btc, offset_bit (Bit Test and Convert) - בדיקה והיפוך מעט. ההוראה עוטפת את הערך של ביט בדגל cf ולאחר מכן הופכת את הערך של הביט הזה.

Shift פקודות

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

כל הוראות ההסטה מזיזות סיביות בשדה האופרנד שמאלה או ימינה בהתאם ל-opcode. לכל הוראות המשמרת יש את אותו מבנה - העתק אופרנד, shift_count.

מספר הביטים שיש להזיז - counter_shifts - ממוקם במקום האופרנד השני וניתן להגדיר אותו בשתי דרכים:

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

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

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

כל הוראות המשמרת קובעות את דגל הנשיאה ראה.

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

ניתן לחלק את פקודות Shift לשני סוגים על פי עקרון הפעולה:

1) פקודות העברה ליניאריות;

2) פקודות העברה מחזוריות.

פקודות העברה ליניאריות

פקודות מסוג זה כוללות פקודות המשתנות לפי האלגוריתם הבא:

1) הביט הבא שנדחף קובע את דגל ה-CF;

2) לביט שהוזן לאופרנד מהקצה השני יש את הערך 0;

3) כאשר הביט הבא מוזז, הוא נכנס לדגל ה-CF, בעוד הערך של הביט המוזז הקודם אובד! פקודות העברה ליניאריות מחולקות לשני סוגים:

1) פקודות תזוזה ליניאריות לוגיות;

2) הוראות העברה ליניארית אריתמטית.

פקודות ההזזה הליניאריות הלוגיות כוללות את הדברים הבאים:

1) shl operand, counter_shifts (Shift Logical Left) - העברה לוגית שמאלה. התוכן של האופרנד מוסט שמאלה במספר הסיביות שצוין על ידי shift_count. מימין (במיקום הסיביות הכי פחות משמעותיות) מוזנים אפסים;

2) shr operand, shift_count (Shift Logical Right) - העברה לוגית ימינה. התוכן של האופרנד מוסט ימינה במספר הסיביות שצוין על ידי shift_count. משמאל (במיקום הסימן המשמעותי ביותר), מוזנים אפסים.

איור 30 מראה כיצד פקודות אלו פועלות.

אורז. 30. תכנית העבודה של פקודות של תזוזה לוגית ליניארית

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

1) sal operand, shift_counter (Shift Arithmetic Left) - העברה אריתמטית שמאלה. התוכן של האופרנד מוסט שמאלה במספר הסיביות שצוין על ידי shift_count. מימין (במיקום הסיביות הפחות משמעותיות), מוזנים אפסים. הוראת ה-sal אינה משמרת את השלט, אלא מגדירה את הדגל עם / במקרה של שינוי סימן עד לסיביות המתקדמת הבאה. אחרת, הפקודה sal זהה בדיוק לפקודה shl;

2) sar operand, shift_count (Shift Arithmetic Right) - העברה אריתמטית ימינה. התוכן של האופרנד מוסט ימינה במספר הסיביות שצוין על ידי shift_count. אפסים מוכנסים לאופרנד משמאל. הפקודה sar משמרת את השלט, ומשחזרת אותו לאחר כל הסטת סיביות.

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

אורז. 31. תכנית הפעולה של פקודות תזוזה אריתמטיות ליניאריות

סובב פקודות

הוראות ההסטה המחזוריות כוללות הוראות המאחסנות את הערכים של הביטים המוזזים. ישנם שני סוגים של הוראות העברה מחזורית:

1) פקודות העברה מחזוריות פשוטות;

2) פקודות העברה מחזוריות באמצעות דגל הנשיאה cf.

פקודות העברה מחזוריות פשוטות כוללות:

1) אופרנד roll, shift_counter (סיבוב שמאלה) - העברה מחזורית שמאלה. התוכן של האופרנד מוסט שמאלה במספר הסיביות שצוין על ידי האופרנד shift_count. סיביות המוזות שמאלה נכתבות לאותו אופרנד מימין;

2) gog operand, counter_shifts (Rotate Right) - העברה מחזורית ימינה. התוכן של האופרנד מוזז ימינה במספר הסיביות שצוין על ידי האופרנד shift_count. סיביות המוזות ימינה נכתבות לאותו אופרנד משמאל.

אורז. 32. תוכנית הפעולה של פקודות של תזוזה מחזורית פשוטה

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

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

הדברים הבאים קשורים לפקודות ההזזה המחזוריות באמצעות דגל הנשיאה:

1) אופרנד rcl, shift_count (Rotate through Carry Left) - העברה מחזורית שמאלה דרך carry.

התוכן של האופרנד מוסט שמאלה במספר הסיביות שצוין על ידי האופרנד shift_count. הביטים המוזזים הופכים בתורם לערך של דגל ה-carrier cf.

2) אופרנד rsg, shift_count (Rotate through Carry Right) - העברה מחזורית ימינה באמצעות Carry.

התוכן של האופרנד מוזז ימינה במספר הסיביות שצוין על ידי האופרנד shift_count. הביטים המוזזים הופכים בתורם לערך של דגל ה-carrier CF.

אורז. 33. סובב הוראות באמצעות Carry Flag CF

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

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

פקודות משמרת נוספות

מערכת הפיקוד של דגמי המיקרו-מעבדים העדכניים ביותר של אינטל, החל מה-i80386, מכילה פקודות Shift נוספות המרחיבות את היכולות עליהן דיברנו קודם. אלו הן פקודות ההסטה הדיוק הכפול:

1) shld operand_1, operand_2, shift_counter - העברה שמאלה דיוק כפול. הפקודה shld מבצעת החלפה על ידי הזזת הסיביות של operand_1 שמאלה, מילוי הסיביות שלה מימין בערכי הביטים שנעקרו מאופרנד_2 לפי התרשים באיור. 34. מספר הסיביות שיש להזיז נקבע על פי ערך shift_counter, שיכול להיות בטווח 0... 31. ערך זה יכול להיות מוגדר כאופרנד מיידי או להכיל את ה-cl register. הערך של operand_2 לא משתנה.

אורז. 34. סכימת הפקודה shld

2) shrd operand_1, operand_2, shift_counter - העברה ימנית דיוק כפול. ההוראה מבצעת את ההחלפה על ידי הזזת הסיביות של האופרנד_1 ימינה, מילוי הסיביות שלו משמאל בערכי הביטים שנעקרו מאופרנד_2 לפי התרשים באיור 35. מספר הביטים שיש להזיז הוא נקבע על ידי הערך של shift_counter, שיכול להיות בטווח 0...31. ערך זה יכול להיות מוגדר על ידי האופרנד המיידי או להכיל את ה-cl register. הערך של operand_2 לא משתנה.

אורז. 35. תכנית הפקודה shrd

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

2. פקודות העברת בקרה

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

1) ללא תנאי - בשלב זה יש צורך להעביר את השליטה לא לפקודה הבאה, אלא לאחרת שנמצאת במרחק מה מהפקודה הנוכחית;

2) מותנה - ההחלטה על איזו פקודה תתבצע הבאה מתקבלת על סמך ניתוח של כמה תנאים או נתונים.

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

איזו הוראת תוכנית צריכה להתבצע לאחר מכן, המיקרו-מעבד לומד מהתוכן של cs: (ה) זוג ip register:

1) cs - אוגר מקטע קוד, המכיל את הכתובת הפיזית (הבסיסית) של מקטע הקוד הנוכחי;

2) eip/ip - אוגר מצביע פקודה, המכיל ערך המייצג את ההיסט בזיכרון של ההוראה הבאה שתתבצע ביחס לתחילת קטע הקוד הנוכחי.

באיזה אוגר מסוים ייעשה שימוש תלוי במצב הכתובת המוגדר use16 או use32. אם צוין שימוש 16, אזי נעשה שימוש ב-ip, אם use32, אזי נעשה שימוש ב-eip.

לפיכך, הוראות העברת בקרה משנות את התוכן של אוגרי cs ו-eip/ip, וכתוצאה מכך המיקרו-מעבד בוחר לביצוע לא את הוראת התוכנית הבאה לפי הסדר, אלא את ההוראה בחלק אחר של התוכנית. הצינור בתוך המיקרו-מעבד מאופס.

על פי עקרון הפעולה, ניתן לחלק את פקודות המיקרו-מעבד המספקות את ארגון המעברים בתוכנית ל-3 קבוצות:

1. העברה ללא תנאי של פקודות שליטה:

1) פקודה סניף ללא תנאי;

2) פקודה לקרוא להליך ולחזור מנוהל;

3) פקודה להתקשר לתוכנה מפריעות ולחזור מפסיקות בתוכנה.

2. פקודות להעברת שליטה מותנית:

1) פקודות קפיצה לפי תוצאת פקודת ההשוואה p;

2) פקודות מעבר לפי מצב דגל מסוים;

3) הוראות לקפיצה דרך התוכן של ה-esx/cx register.

3. מחזור פקודות בקרה:

1) פקודה לארגון מחזור עם מונה ехх/сх;

2) פקודה לארגון מחזור עם מונה ех/сх עם אפשרות ליציאה מוקדמת מהמחזור בתנאי נוסף.

קפיצות ללא תנאי

הדיון הקודם חשף כמה פרטים על מנגנון המעבר. הוראות קפיצה משנות את אוגר מצביעי הוראות eip/ip ואולי את אוגר מקטע קוד cs. מה בדיוק צריך לשנות תלוי ב:

1) על סוג האופרנד בהוראת הענף הבלתי מותנית (קרוב או רחוק);

2) מציון משנה לפני כתובת הקפיצה (בהוראת הקפיצה); במקרה זה, כתובת הקפיצה עצמה יכולה להיות ממוקמת ישירות בהוראה (קפיצה ישירה), או בתא אוגר או זיכרון (קפיצה עקיפה).

השינוי יכול לקחת את הערכים הבאים:

1) near ptr - מעבר ישיר לתווית בתוך קטע הקוד הנוכחי. רק אוגר ה-eip/ip משתנה (בהתאם לסוג מקטע הקוד use16 או use32 שצוין) בהתבסס על הכתובת (התווית) שצוינה בפקודה או ביטוי באמצעות סמל חילוץ הערך - $;

2) far ptr - מעבר ישיר לתווית בקטע קוד אחר. כתובת הקפיצה מצוינת כאופרנד מיידי או ככתובת (תווית) והיא מורכבת מבורר של 16 סיביות והיסט של 16/32 סיביות, אשר נטענים לתוך אוגרי cs ו-ip/eip, בהתאמה;

3) word ptr - מעבר עקיף לתווית בתוך קטע הקוד הנוכחי. רק eip/ip משתנה (על ידי ערך ההיסט מהזיכרון בכתובת שצוינה בפקודה, או מפנקס). גודל אופסט 16 או 32 סיביות;

4) dword ptr - מעבר עקיף לתווית בקטע קוד אחר. שני האוגרים - cs ו-eip / ip - משתנים (על ידי ערך מהזיכרון - ורק מהזיכרון, מאוגר). המילה/dword הראשונה של כתובת זו מייצגת את ההיסט ונטענת לתוך ip/eip; המילה השנייה/שלישית נטענת לתוך cs. הוראת קפיצה ללא תנאי של jmp

תחביר הפקודה לקפיצה בלתי מותנית הוא jmp [modifier] jump_address - קפיצה בלתי מותנית ללא שמירת מידע על נקודת ההחזרה.

Jump_address היא הכתובת בצורה של תווית או הכתובת של אזור הזיכרון שבו נמצא מצביע הזינוק.

בסך הכל, במערכת הוראות המיקרו-מעבד ישנם מספר קודים של הוראות מכונה לקפיצה ללא תנאי jmp.

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

ישנן שלוש אפשרויות לשימוש תוך-מקטע בפקודה jmp:

1) ישר קצר;

2) ישר;

3) עקיף.

נהלים

לשפת Assembly יש כמה כלים הפותרים את הבעיה של שכפול קטעי קוד. אלו כוללים:

1) מנגנון של נהלים;

2) מאקרו מאקרו;

3) מנגנון פסיקה.

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

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

כדי לתאר רצף של פקודות כנוהל בשפת assembly, נעשה שימוש בשתי הנחיות: PROC ו-ENDP.

תחביר תיאור ההליך הוא כדלקמן (איור 36).

אורז. 36. תחביר של תיאור ההליך בתוכנית

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

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

קפיצות מותנות

למיקרו-מעבד 18 הוראות קפיצה מותנות. פקודות אלה מאפשרות לך לבדוק:

1) היחס בין אופרנדים עם סימן ("גדול - פחות");

2) היחס בין אופרנדים ללא סימן ("גבוה יותר - נמוך יותר");

3) מצבים של דגלים אריתמטיים ZF, SF, CF, OF, PF (אך לא AF).

לפקודות קפיצה מותנית יש את אותו תחביר:

jcc jump_label

כפי שאתה יכול לראות, הקוד המנמוני של כל הפקודות מתחיל ב-"j" - מהמילה קפיצה (קפיצה), הוא קובע את המצב הספציפי המנותח על ידי הפקודה.

באשר לאופרנד jump_label, תווית זו יכולה להיות ממוקמת רק בתוך מקטע הקוד הנוכחי; העברת שליטה בין מקטעים בקפיצות מותנות אינה מותרת. בהקשר זה, אין עוררין על המשנה, שהיה קיים בתחביר של פקודות הקפיצה הבלתי מותנות. בדגמים מוקדמים של המיקרו-מעבד (i8086, i80186 ו-i80286), הוראות הסתעפות מותנות יכלו לבצע רק קפיצות קצרות - מ-128 עד +127 בתים מההוראה בעקבות הוראת הסניף המותנית. החל מדגם מיקרו-מעבד 80386, הגבלה זו מוסרת, אך, כפי שניתן לראות, רק בקטע הקוד הנוכחי.

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

מקורות למצב כזה יכולים להיות:

1) כל פקודה המשנה את מצב דגלים אריתמטיים;

2) הוראת ההשוואה p, המשווה את הערכים של שני אופרנדים;

3) מצב האוגר esx/cx.

הפקודה להשוות cmp

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

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

תחביר הפקודה str - str operand_1, operand_2 (השוואה) - משווה שני אופרנדים ומגדיר דגלים על סמך תוצאות ההשוואה.

ניתן לנתח את הדגלים שנקבעו על ידי הפקודה p על ידי הוראות ענף מותנה מיוחדות. לפני שנסתכל עליהם, הבה נשים לב מעט למנמוניות של הוראות הקפיצה המותנית הללו (טבלה 16). הבנת הסימון בעת ​​יצירת השם של פקודות הקפיצה המותנית (האלמנט בשם הפקודה jcc, היינו אותו) תקל על שינון שלהן ועל שימוש מעשי נוסף.

טבלה 16. משמעות הקיצורים בשם הפקודה jcc טבלה 17. רשימת פקודות קפיצה מותנות עבור הפקודה p operand_1, operand_2

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

הוראות סניף מותנה ודגלים

הכינוי המנמוני של כמה הוראות קפיצה מותנות משקף את שם הדגל שאיתו הם עובדים, ויש לו את המבנה הבא: התו הראשון הוא "j" (קפיצה, קפיצה), השני הוא ייעוד הדגל או תו השלילה " n", ואחריו שם הדגל . מבנה צוות זה משקף את מטרתו. אם אין תו "n", אזי מסומן מצב הדגל, אם הוא שווה ל-1, מתבצע מעבר לתווית הקפיצה. אם התו "n" קיים, אזי מדינת הדגל נבדקת עבור שוויון ל-0, ואם היא מצליחה, מתבצעת קפיצה לתווית הקפיצה.

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

טבלה 18. הוראות קפיצה מותנית ודגלים

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

הוראות קפיצה מותנית והרשמת esx/cx

הארכיטקטורה של המיקרו-מעבד כוללת שימוש ספציפי ברישומים רבים. לדוגמה, האוגר EAX / AX / AL משמש כמצבר, ואוגרי BP, SP משמשים לעבודה עם המחסנית. גם לאגר ECX / CX יש מטרה פונקציונלית מסוימת: הוא פועל כמונה בפקודות בקרת לולאה ובעבודה עם מחרוזות תווים. יתכן שמבחינה פונקציונלית, הוראת הסניף המותנית הקשורה לאגר esx/cx תיוחס בצורה נכונה יותר לקבוצת הוראות זו.

התחביר עבור הוראת ענף מותנית זו הוא:

1) jcxz jump_label (קפיצה אם ex הוא אפס) - קפוץ אם cx הוא אפס;

2) jecxz jump_label (Jump Equal ех Zero) - קפוץ אם ех הוא אפס.

פקודות אלו שימושיות מאוד בעת לולאה וכאשר עובדים עם מחרוזות תווים.

יש לציין כי ישנה מגבלה הטבועה בפקודה jcxz/jecxz. בניגוד להוראות העברה מותנית אחרות, הוראת jcxz/jecxz יכולה להתייחס רק לקפיצות קצרות -128 בתים או +127 בתים מההוראה שאחריה.

ארגון מחזורים

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

בואו ניתן תיאור קצר של הפקודות הללו:

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

א) הפחתה של פנקס ECX/CX;

ב) השוואת האוגר ECX/CX עם אפס: אם (ECX/CX) = 0, אז השליטה מועברת לפקודה הבאה אחרי הלולאה;

2) loope/loopz jump_label

הפקודות loope ו-loopz הן מילים נרדפות מוחלטות. עבודת הפקודות היא לבצע את הפעולות הבאות:

א) הפחתה של פנקס ECX/CX;

ב) השוואת אוגר ECX/CX עם אפס;

ג) ניתוח המצב של דגל האפס ZF אם (ECX/CX) = 0 או XF = 0, השליטה מועברת לפקודה הבאה אחרי לולאה.

3) loopne/loopnz jump_label

הפקודות loopne ו-loopnz הן גם מילים נרדפות מוחלטות. עבודת הפקודות היא לבצע את הפעולות הבאות:

א) הפחתה של פנקס ECX/CX;

ב) השוואת אוגר ECX/CX עם אפס;

ג) ניתוח המצב של דגל האפס ZF: אם (ECX/CX) = 0 או ZF = 1, השליטה מועברת לפקודה הבאה אחרי הלולאה.

הפקודות loope/loopz ו-loopne/loopnz הן הדדיות בפעולתן. הם מרחיבים את הפעולה של פקודת הלולאה על ידי ניתוח נוסף של דגל zf, מה שמאפשר לארגן יציאה מוקדמת מהלולאה, תוך שימוש בדגל זה כאינדיקטור.

החיסרון של פקודות הלופינג loop, loope/loopz ו-loopne/loopnz הוא שהן מיישמות רק קפיצות קצרות (מ-128 עד +127 בתים). כדי לעבוד עם לולאות ארוכות, תצטרך להשתמש בקפיצות מותנות ובהוראת jmp, אז נסה לשלוט בשתי הדרכים לארגון לולאות.

מחבר: Tsvetkova A.V.

אנו ממליצים על מאמרים מעניינים סעיף הערות הרצאה, דפי רמאות:

מיסים ומיסוי. עריסה

סחורה. עריסה

אינפורמטיקה וטכנולוגיות מידע. הערות הרצאה

ראה מאמרים אחרים סעיף הערות הרצאה, דפי רמאות.

תקרא ותכתוב שימושי הערות על מאמר זה.

<< חזרה

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

עור מלאכותי לחיקוי מגע 15.04.2024

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

פסולת חתולים של Petgugu Global 15.04.2024

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

האטרקטיביות של גברים אכפתיים 14.04.2024

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

חדשות אקראיות מהארכיון

רשתות סלולריות 5G 07.10.2013

NTT DoCoMo ב-CEATEC 2013 ביפן שיתפה את התוכניות הראשוניות שלה לפריסת רשתות סלולריות מהדור החמישי (5G).

רשתות LTE מודרניות (4G) מספקות בתיאוריה קצבי העברת נתונים של עד 326,4 Mbps עבור קליטה ועד 172,8 Mbps להעלאה. ברור שבתנאים אמיתיים התפוקה נמוכה בהרבה.

מערכות התקשורת הניידות מהדור החמישי יביאו את קצב העברת הנתונים לרמה חדשה מבחינה איכותית. NTT DoCoMo מדבר על עלייה של פי 100 לעומת LTE.

ההנחה היא שהחברה היפנית תשתמש בתדרים מעל 3 גיגה-הרץ. NTT DoCoMo מתכננת להשתמש בתחנות בסיס קטנות נוספות כדי לשפר את איכות השיחה ולשפר את היציבות של השירותים הניידים.

הפריסה של רשתות 5G תחל בסביבות 2020.

חברות אחרות מפתחות גם רשתות סלולריות 5G. לדוגמה, Huawei מצפה להתחיל בפריסה מסחרית של טכנולוגיה אלחוטית מהדור החמישי בסוף העשור, המסוגלת לספק העברת נתונים במהירויות של עד 10 Gb/s.

עוד חדשות מעניינות:

▪ אופנוע אש

▪ סמארטפונים עם סים כפול Panasonic P50 Idol ו-P65 Flash.

▪ שרת מוזיקה במעבד ARM

▪ כונן הבזק 16 גיגה

▪ פעילות וולקנית לא טיפוסית הבחינה באירופה

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

 

חומרים מעניינים של הספרייה הטכנית החופשית:

▪ קטע אתר ציוד ריתוך. בחירת מאמרים

▪ מאמר האם אני אוהב אותך, אני לא יודע, אבל נראה לי שאני אוהב אותך! ביטוי עממי

▪ מאמר אילו נהרות בעולם נמצאים בעשירייה הראשונה מבחינת אורך? תשובה מפורטת

▪ מאמר אחות. תיאור משרה

▪ מאמר דיו טיפוגרפי. מתכונים וטיפים פשוטים

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

השאר את תגובתך למאמר זה:

שם:


אימייל (אופציונלי):


להגיב:





כל השפות של דף זה

בית | הספרייה | מאמרים | <font><font>מפת אתר</font></font> | ביקורות על האתר

www.diagram.com.ua

www.diagram.com.ua
2000-2024