سلام به کاربران و همراهان روکسو. در این قسمت از آموزش به بحث پیشپردازندهها (Preprocessors) در ++C/C خواهیم پرداخت، تا پایان ما را همراهی کنید.
همانطور که از نام آنها مشخص است، پیشپردازندهها برنامههایی هستند که کد منبعمان را قبل از عمل کامپایل کردن، پردازش میکنند. تعدادی گام بین نوشتن یک برنامه و اجرای آن در ++C/C وجود دارد. اجازه دهید که قبل از اینکه عملا شروع به یادگیری درمورد پیشپردازندهها کنیم، نگاهی به این گامها داشته باشیم.
میتوانید گامهای وسطی در دیاگرام بالا را مشاهده کنید. کدمنبع نوشته شده توسط برنامهنویسان در فایل program.c ذخیره شده است. این فایل توسط پیشپردازندهها پردازش شده است و فایل کدمنبع گسترش داده شده با نام program ایجادشده است. این فایل گسترش دادهشده توسط کامپایلر، کامپایل شدهاست و فایل کدشیء (object code) با نام program .obj ایجاد شده است. درنهایت، لینکر (linker) این فایل کدشیء را با کد شیء توابع کتابخانه برای تولید فایلی اجرایی (executable file) یعنی program.exe پیوند یا همان لینک میدهد.
برنامههای پیشپردازنده، دستورات پیشپردازندهای را فراهم میکنند که به کامپایلر میگویند کدمنبع را قبل از عمل کامپایلکردن، پیشپردازش کند. همهی این دستورات پیشپردازنده با علامت هَش (#) شروع میشوند. علامت # نشان میدهد که هر دستوری که با # شروع شود، توسط برنامهی پیشپردازنده اجرا خواهد شد. مثالی از برخی دستورات پیشپردازنده شامل: include, #define, #ifndef# و غیره است.
به خاطر داشته باشید که علامت # تنها مسیری که به پیشپردازنده ختم میشود را فراهم میکند و دستوری مانند include توسط برنامهی پیشپردازنده پردازش میشود. برای مثال، دستوری include، کد اضافه را به برنامهتان اضافه میکند. میتوان در هر جایی از برنامه، از این دستورات پیشپردازنده استفاده کرد.
بیاید در جزئیات بیشتر هر کدام از این دستورات را یاد بگیریم.
ماکروها، کدهایی در برنامه هستند که از نام تشکیل شدهاند. هرگاه کامپایلر به این نامها برخورد کند، کامپایل نام را با قطعهکد واقعی جایگزین میکند. دستور define# برای تعریف یک ماکرو استفاده شده است. برای درک تعریف ماکرو، مثال زیر را مشاهده کنید که در زبان ++C است:
#include <iostream> // macro definition #define LIMIT 5 int main() { for (int i = 0; i < LIMIT; i++) { std::cout << i << "\n"; } return 0; }
همچنین قطعهکد آن به زبان C به این صورت است:
#include <stdio.h> // 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 را اجرا کند، کامپایلر، LIMIT را با 5 جایگزین میکند. کلمهی LIMIT در تعریف ماکرو، یک الگوی ماکرو (macro template) نامیده میشود و 5 گسترش ماکرو است.
نکته: سِمیکالن ( ; ) در انتهای تعریف ماکرو وجود ندارد. ماکروها نیازی به سمیکالن ندارند.
ماکروها با آرگومان (Macros with arguments): میتوان آرگومانها را به ماکروها ارسال کرد. ماکرو تعریفشده با آرگومان همانند توابع عمل میکنند. قطعهکد زیر را برای درک بهتر این موضوع مشاهده کنید که در زبان ++C آماده شده است:
#include <iostream> // macro with parameter #define AREA(l, b) (l * b) int main() { int l1 = 10, l2 = 5, area; area = AREA(l1, l2); std::cout << "Area of rectangle is: " << area; return 0; }
همچنین قطعهکد آن به زبان C به این صورت است:
#include <stdio.h> // macro with parameter #define AREA(l, b) (l * b) int main() { int l1 = 10, l2 = 5, area; area = AREA(l1, l2); printf("Area of rectangle is: %d", area); return 0; }
خروجی قطعهکد بالا به این صورت است:
Area of rectangle is: 50
میتوان از قطعهکد بالا متوجه شد که هر زمان که کامپایلر در برنامه به AREA(l, b) برخورد کند، AREA(l, b) را با دستور (l*b) جایگزین خواهد کرد. نه تنها این، بلکه مقادیر ارسالشده به الگوی ماکرو AREA(l, b) نیز در دستور statement (l*b) جایگزین خواهد شد. بنابراین AREA(10, 5) برابر خواهد بود با 10*5.
این نوع از دستور پیشپردازنده به کامپایلر اعلام میکند که یک فایل در کدمنبع برنامه اضافه کند. 2 نوع از فایلهایی که میتواند توسط کاربر در برنامه اضافه شود، شامل:
#include< file_name >
file_name نام فایلی از است که اضافهشده است. دو قلاب یا براکت ( <> ) به کامپایلر اعلام میکند که به دنبال فایل در دایرکتوری استاندارد باشد.
#include"filename"
دستور شرط کامپایل یا Conditional Compilation نوعی از دستورات هستند که یک بخش خاص از برنامه را کامپایل می کنند یا رد شدن از کامپایل کردن برخی از بخشهای خاص برنامه را براساس تعدادی شرط تعیین میکنند. این کار میتواند بااستفاده از 2 دستور پیشپردازنده با نامهای ifdef وendif صورت گیرد. نحو یا Syntax آن به این صورت است:
#ifdef macro_name statement1; statement2; statement3; . . . statementN; #endif
اگر ماکرو با نام macroname تعریف شده باشد، دستورات اجرا خواهند شد. اما اگر تعریف نشده باشد، کامپایلر به سادگی دستورات را نادیده میگیرد.
جدا از دستورات بالا، بیش از 2 دستور که استفاده از آنها رایج نیست، وجود دارد:
#undef LIMIT
بااستفاده از این دستور ماکرو LIMIT که موجود است، نامشخص میشود. بعد از این دستور، هر دستور ifdef #LIMIT به false ارزیابی میشود.
1. دستور pragma#: این دستور یک دستور خاص است و برای فعال یا غیرفعال کردن برخی ویژگیها استفاده شده است. این نوع دستورات مشخصکنندهی کامپایلر یا compiler-specific هستند. به عنوان مثال، آنها از کامپایلری به کامپایلری تغییر میدهند. برخی از دستورات pragma# به این صورت است:
نکته: قطعهکد زیر با کامپایلرهای GCC کار نخواهد کرد.
قطعهکد زیر را مشاهده کنید که در زبان ++C نوشته شده است:
#include <bits/stdc++.h> using namespace std; void func1(); void func2(); #pragma startup func1 #pragma exit func2 void func1() { cout << "Inside func1()\n"; } void func2() { cout << "Inside func2()\n"; } int main() { void func1(); void func2(); cout << "Inside main()\n"; return 0; } // This code is contributed by shivanisinghss2110
همچنین قطعهکد آن به زبان C به این صورت است:
#include <stdio.h> void func1(); void func2(); #pragma startup func1 #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 func1() Inside main() Inside func2()
قطعهکد بالا هنگامی که با کامپایلرهای GCC اجرا شود، خروجی زیر را تولید خواهد کرد:
Inside main()
این به این خاطر است که GCC از pragma startup # یا exit پشتیبانی نمیکند. با این حال، میتوانید از قطعهکد زیر برای خروجی مشابه در کامپایلرهای GCC استفاده کنید.
قطعهکد زیر را که در زبان ++C است، مشاهده کنید:
#include <iostream> using namespace std; void func1(); void func2(); void __attribute__((constructor)) func1(); void __attribute__((destructor)) func2(); void func1() { printf("Inside func1()\n"); } void func2() { printf("Inside func2()\n"); } // Driver code int main() { printf("Inside main()\n"); return 0; } //
همچنین قطعهکد آن به زبان C به این صورت است:
#include <stdio.h> void 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; }
2. دستور pragma warn#: این دستور برای مخفی کردن پیغام هشدار که در طی کامپایلکردن نمایش داده میشوند، استفاده میشود.
منبع: وب سایت geeksforgeeks
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.