C Preprocessors
מעבדי קדם הן תוכנות שמעבדות את קוד המקור לפני תחילת ההידור בפועל. הם אינם חלק מתהליך ההידור אלא פועלים בנפרד ומאפשרים למתכנתים לשנות את הקוד לפני ההידור.
- זהו השלב הראשון שעובר קוד המקור C בעת ההמרה לקובץ הפעלה.
- הסוגים העיקריים של הנחיות קדם-מעבד הם מאקרו הידור מותנה של הכללת קבצים והנחיות אחרות כמו #undef #pragma וכו'.
- בעיקר הנחיות אלו משמשות כדי להחליף קטע נתון של קוד C בקוד C אחר. לדוגמה, אם נכתוב '#define PI 3.14' אז PI מוחלף ב-3.14 על ידי הפרה-מעבד.
סוגי Preprocessors C
ניתן לסווג את כל הפרה-מעבדים לעיל ל-4 סוגים:
מאקרו
מאקרו משמשים להגדרת קבועים או ליצירת פונקציות המוחלפות על ידי המעבד הקדם לפני הידור הקוד. שני המעבדים הקדם #לְהַגדִיר ו #undef משמשים ליצירה והסרה של פקודות מאקרו ב-C.
#לְהַגדִיר ערך סמלי
#undef אֲסִימוֹן
שבו לאחר עיבוד מקדים את אֲסִימוֹן יורחב לזה עֵרֶך בתוכנית.
דוּגמָה:
C #include // Macro Definition #define LIMIT 5 int main (){ for ( int i = 0 ; i < LIMIT ; i ++ ) { printf ( '%d n ' i ); } return 0 ; }
תְפוּקָה
0 1 2 3 4
בתוכנית לעיל לפני תחילת הקומפילציה המילה LIMIT מוחלפת ב-5. המילה 'לְהַגבִּיל' בהגדרת המאקרו נקראת תבנית מאקרו ו '5' הוא הרחבת מאקרו.
פֶּתֶק אין נקודה-פסיק (;) בסוף הגדרת המאקרו. הגדרות מאקרו אינן צריכות נקודה-פסיק כדי להסתיים.
יש גם כמה מאקרו מוגדרים מראש ב-C אשר שימושיים במתן פונקציות שונות לתוכנית שלנו.
מאקרו שהוגדר בעבר יכול להיות לא מוגדר באמצעות מעבד קדם-#undef. למשל בקוד למעלה
C #include // Macro Definition #define LIMIT 5 // Undefine macro #undef LIMIT int main (){ for ( int i = 0 ; i < LIMIT ; i ++ ) { printf ( '%d n ' i ); } return 0 ; }
תְפוּקָה:
./Solution.c: In function 'main': ./Solution.c:13:28: error: 'MAX' undeclared (first use in this function) printf('MAX is: %dn' MAX); ^ ./Solution.c:13:28: note: each undeclared identifier is reported only once for each function it appears inמאקרו עם ויכוחים
אנחנו יכולים גם להעביר ארגומנטים לפקודות מאקרו. פקודות מאקרו אלו פועלות באופן דומה לפונקציות. לְדוּגמָה
# לְהַגדִיר foo(a b) a + b
#define func(r) r * rתן לנו להבין את זה עם תוכנית:
C#include// macro with parameter #define AREA(l b) (l * b) int main (){ int a = 10 b = 5 ; // Finding area using above macro printf ( '%d' AREA ( a b )); return 0 ; }
תְפוּקָהArea of rectangle is: 50הֶסבֵּר: בתוכנית לעיל המאקרו AREA(l b) מוגדר לחשב את השטח של מלבן על ידי הכפלה שלו אורך (l) ו רוחב (ב) . כַּאֲשֵׁר AREA(א ב) נקרא זה מתרחב ל (א*ב) והתוצאה מחושבת ומודפסת.
אנא עיין סוגי מאקרו ב-C לדוגמאות וסוגים נוספים.
הכללת קובץ
הכללת קבצים מאפשרת לך לכלול קבצים חיצוניים (ספריות קבצי כותרות וכו') בתוכנית הנוכחית. זה נעשה בדרך כלל באמצעות #לִכלוֹל הנחיה שיכולה לכלול גם קבצים מוגדרי מערכת וגם קבצים מוגדרים על ידי המשתמש.
תַחבִּיר
ישנן שתי דרכים לכלול קובצי כותרות.
#לִכלוֹל
#לִכלוֹל 'שם קובץ'ה ' <' ו '>' בסוגריים תגיד למהדר לחפש את הקובץ ב- ספרייה רגילה בְּעוֹד מרכאות כפולות ( ' ' ) תגיד למהדר לחפש את קובץ הכותרת בספריית קובץ המקור.
דוּגמָה:
C// Includes the standard I/O library #includeint main () { printf ( 'Hello World' ); return 0 ; }
תְפוּקָהHello Worldקומפילציה מותנית
קומפילציה מותנית מאפשר לך לכלול או לא לכלול חלקים מהקוד בהתאם לתנאים מסוימים. זה שימושי ליצירת קוד ספציפי לפלטפורמה או לניפוי באגים. יש את הנחיות הקדם-מעבד המותנות הבאות: #if #ifdef #ifndef else #elif ו-#endif
תַחבִּיר
התחביר הכללי של מעבדי קדם מותנים הוא:
#אִם
// קוד כלשהו
#elif
// עוד קצת קוד
#אַחֵר
// עוד קצת קוד
#endifההנחיה #endif משמשת לסגירת הנחיות הפתיחה #if #ifdef ו-#ifndef.
דוּגמָה
C#include// Defining a macro for PI #define PI 3.14159 int main (){ // Check if PI is defined using #ifdef #ifdef PI printf ( 'PI is defined n ' ); // If PI is not defined check if SQUARE is defined #elif defined(SQUARE) printf ( 'Square is defined n ' ); // If neither PI nor SQUARE is defined trigger an error #else #error 'Neither PI nor SQUARE is defined' #endif // Check if SQUARE is not defined using #ifndef #ifndef SQUARE printf ( 'Square is not defined' ); // If SQUARE is defined print that it is defined #else printf ( 'Square is defined' ); #endif return 0 ; }
תְפוּקָהPI is defined Square is not definedהֶסבֵּר: קוד זה משתמש בהנחיות קדם-מעבד מותנות ( #ifdef #elif ו #ifndef ) כדי לבדוק אם פקודות מאקרו מסוימות ( פַּיִי ו מְרוּבָּע ) מוגדרים. מכיוון ש-PI מוגדר, התוכנית מדפיסה ' PI מוגדר ' ואז בודק אם SQUARE אינו מוגדר ומדפיס ' ריבוע אינו מוגדר '.
הנחיות אחרות
מלבד הנחיות הקדם-מעבד הראשיות C מספקת גם הנחיות אחרות לניהול התנהגות מהדר וניפוי באגים.
#פרגמה:
מספק הנחיות ספציפיות למהדר כדי לשלוט בהתנהגותו. הוא משמש לביטול יישור ערכות אזהרות וכו'.
תַחבִּיר
#פרגמה הוֹרָאָה
חלק מהנחיות #pragma נדונות להלן:
- #פרגמה סטארט-אפ: הנחיות אלו עוזרות לנו לציין את הפונקציות הדרושות להפעלה לפני הפעלת התוכנית (לפני שהפקד עובר ל-main()).
- יציאה #פרגמה : הנחיות אלו עוזרות לנו לציין את הפונקציות הדרושות להפעלה ממש לפני יציאת התוכנית (ממש לפני שהפקד חוזר מ-main()).
דוּגמָה
C#includevoid func1 (); void func2 (); // specifying funct1 to execute at start #pragma startup func1 // specifying funct2 to execute before end #pragma exit func2 void func1 () { printf ( 'Inside func1() n ' ); } void func2 () { printf ( 'Inside func2() n ' ); } int main (){ void func1 (); void func2 (); printf ( 'Inside main() n ' ); return 0 ; }
תְפוּקָהInside main()הקוד לעיל יפיק את הפלט כפי שניתן לעיל כאשר הוא רץ על מהדרים של GCC בעוד שהפלט הצפוי היה:
פלט צפוי
Inside func1() Inside main() Inside func2()זה קורה מכיוון ש-GCC לא תומך בהפעלה או יציאה של #pragma. עם זאת, אתה יכול להשתמש בקוד שלהלן עבור הפלט הצפוי במהדרים של GCC.
C#includevoid func1 (); void func2 (); void __attribute__ (( constructor )) func1 (); void __attribute__ (( destructor )) func2 (); void func1 () { printf ( 'Inside func1() n ' ); } void func2 () { printf ( 'Inside func2() n ' ); } int main () { printf ( 'Inside main() n ' ); return 0 ; }
תְפוּקָהInside func1() Inside main() Inside func2()בתוכנית לעיל השתמשנו בכמה תחבירים ספציפיים כך שאחת הפונקציות מופעלת לפני הפונקציה הראשית והשנייה מופעלת אחרי הפונקציה הראשית.
צור חידון