אני לא כל-כך מבין מה לא ברור לך
אם בא לך, תעלה כמה ביטויים, וננסה כולנו להבין איך הקומפיילרים מנתחים ומבצעים אותם. בגדול, אני לא הגדרתי
סדר בהודעה שלי, אלא הגדרתי ארבעה מושגים כדי שנוכל לדבר על כל אחד מהם בנפרד. ההפרדה הזו חשובה, כדי שלא נתבלבל בין 1 ו-2 שם, precedence ו-associativity, שקובעים איך הקומפיילר מפרש את הביטוי (אמרתי שם, איך הוא "שם סוגריים" כדי שהוא יוכל "להבין" את הביטוי באופן חד-חד-ערכי), לבין איך הוא יבצע אותו. אני אסביר קצת יותר. CL, הקומפיילר של מיקרוסופט, הוא למעשה שלוש אפליקציות: pre-processor, compiler, optimizer. זה אומר, לדוגמא, שיש חלקים של תוכניות שלא יהפכו בכלל לאסמבלר כי ה-optimizer יגלה שהם לעולם לא יקרו, ויעיף אותם. לדוגמא, בביטוי לוגי כזה:
bool a = true || (3 + 4 * 5 * 234.4)
כל החלק שאחרי ה-|| לא יגיע לאסמבלר בכלל, כי כבר
בזמן קומפילציה האופטימייזר רואה שאין צורך לחשב את הביטוי השני (מעניין לבדוק מה קורה כשיש לחלק השני side-effects, אבל שוב, זה נושא נפרד, שעשוי להשתלב, אבל לא חייב). אם החלק שלפני ה-|| לא יכול להיות ידוע בזמן קומפילציה, בזמן ריצה הוא יבדק, ואם לא יהיה בו צורך, הוא לא יתבצע.
בכל מקרה שתי האפשרויות, אופטימייזר וזמן ריצה, שתיהן
אחרי קומפילציה, ובפרט, אחרי השלב בו מוגדרים הביטויים בקומפילציה. גם בלי הבנה בקומפיילרים אפשר לראות שכדי שהקומפיילר יוכל להבין איזה חלק יכול להיות מקוצר, או מושמט, חייב להיות שלב שמחלק את הביטויים כך שהוא יוכל לאכול אותם. לכן, קודם כל, שלבים 1 ו-2. אחר כך, אם יש ביטויים לוגיים יופעל ה-SC, בזמן קומפילציה או בזמן ריצה. במקרה הראשון, לא יהיה לקוד הזה זכר באסמבלר. במקרה השני, הקוד יהיה, אבל יש מחויבות לכך שהוא לא יתבצע. זו נקודה חשובה! הסטנדרט מגדיר שצריך להיות SC, כלומר שאתה יכול להיות בטוח שקוד כזה:
int * p = 0; if (p && p->m = 2)
לא ירסק את המכונה בגלל החצי השני, כש-p לא מוגדר. איך הקומפיילר מממש את זה, זו בעיה של המממש.
אתה כמתכנת יכול לבנות על זה. זהו, אני חושב.