לפני לא פחות מ-5 שנים, Luca Bolognese כתב פוסט שעסק בשאלה שעלתה ב-C# User Group. השאלה היתה מה יהיה הערך של x, בסוף ביצוע קטע הקוד הבא:
אם
אנחנו זוכרים את ההבדל בין Postfix ו-Prefix, אז לא צריכה להיות יותר מדי
בעיה להבין שהתוצאה תהיה בסוף 6 מאחר ואין משמעות ל++ האחרון. כך שלמעשה, ניתן לפשט את הביטוי הזה ל: x = x + x, ועדיין נקבל את אותה ההתנהגות (שימו לב שזה המקרה ב-#C. ב-CPP למשל,
אין הגדרה אמיתית לגבי מה הביטוי הזה צריך להחזיר).
אם כך, זאת נקודת הפתיחה שלנו. הרשתי לעצמי לקחת צעד אחד קדימה ולכתוב את שורת הקוד המאוד קריאה וברורה הזאת:
int x = 10;
x = --x + x + --x;
טוב, אז זה השלב שבו הדברים מתחילים להיות קצת יותר מעניינים.
מה
לפי דעתכם יהיה הערך של x בסוף השורה המופלאה הזאת? אני מציע לקחת דקה של
התבוננות עצמית ומחשבה, סך הכל הביטוי הזה יכול לעורר לא מעט בלבלול.
מוכנים עם התשובה? ובכן, בסופו של דבר הערך של x יהיה 26. למה? הרמז נמצא בכותרת של הפוסט.
מה
שמבלבל בביטוי הזה, הוא שאנחנו כל הזמן צריכים לעקוב היכן בזכרון נשמרים
הערכים במהלך החישוב. האם הנתון נמצא במשתנה המקורי? האם ברג'יסטר של
המעבד? או אולי בכלל במקום אחר? מה שחשוב לשים לב אליו כאן הוא שבמהלך
החישוב אנחנו למעשה מקצים int נוסף שישב על ה-stack, וישמור את "תוצאת
הביניים" של החישוב.
בצעד הראשון, אנחנו מורידים ב-1 את ערכו של x,
ומעדכנים את המשתנה בזכרון, כלומר ברגע זה x=9. לאחר מכן, אנחנו מחברים את x
ב-x. את התוצאה של החישוב הזה אנחנו למעשה נשמור במשתנה זמני נוסף שיוקצה
במיוחד למטרה הזאת על ה-stack. שימו לב לא להתבלבל, אנחנו
לא
מעדכנים את ערכו של x במקרה הזה. לאחר מכן, אנחנו מורידים שוב ב-1 את ערכו
של x (עכשיו ל-8), ואז מחברים אותו למשתנה הזמני ממקודם (שערכו 18). את
התוצאה של החישוב האחרון הזה, נשמור בתוך x. כך קיבלנו בסופו של דבר את התוצאה 26.
אפשר לראות את התהליך הזה בבירור ברגע שאנחנו בודקים את קוד האסמבלר שנוצר לנו בזמן הריצה: