پیش پردازنده در زبان C
پیش پردازنده جزء کامپایلر زبان C نیست بلکه یک مرحله جداگانه در فرآیند کامپایل برنامه است. به عبارت دیگر پیش پردازنده فقط یک ابزار جایگزینی متن است و این عمل را قبل از کامپایل شدن برنامه انجام می دهد. CPP نامی است که به اختصار به آن می گویند و مخفف C Preprocessor می باشد. تمام دستورات پیش پردازنده در زبان برنامه نویسی C با نماد # آغاز می شوند. در جدول زیر دستورات پیش پردازنده مهم در زبان C را مشاهده می کنید:
ردیف | توضیحات |
1 | #define یک ماکرو پیش پردازنده را جایگزین می کند. |
2 | #include یک فایل هدر را به برنامه اضافه می کند. |
3 | #undef ماکرو تعریف شده توسط دستور #define را حذف می کند. |
4 | #ifdef اگر این ماکرو تعریف شده باشد، true باز می گرداند. |
5 | #ifndef اگر این ماکرو تعریف نشده باشد، true باز می گرداند. |
6 | #if دستور شرطی زمان کامپایل است. |
7 | #else جایگزینی برای #if در صورتی که شرط بررسی شده درست نباشد. |
8 | #elif #if و #else در یک دستور. |
9 | #endif بخش شرطی پیش پردازنده را خاتمه می دهد. |
10 | #error پیام خطا را در stderr تنظیم می کند. |
11 | #pragma با استفاده از یک روش استاندارد، دستورالعمل های خاصی را برای کامپایلر انجام می دهد. |
مثال های پیش پردازنده
برای درک بهتر موضوع پیش پردازنده، مثال های زیر را بررسی کنید.
1 | #define MAX_ARRAY_LENGTH 20 |
دستور فوق برای جایگزینی MAX_ARRAY_LENGTH با مقدار 20 استفاده می شود. یعنی هر کجایی برنامه از MAX_ARRAY_LENGTH استفاده کنید، هنگام کامپایل با 20 جایگزین می شود.
1 2 | #include <stdio.h> #include "myheader.h" |
دستور فوق یعنی #include فایل های header مختلف را به برنامه اضافه می کند. خط اول برای اضافه کردن فایل های سیستمی است و خط دوم هم فایل هایی که توسط برنامه نویس نوشته شده است را اضافه می کند.
1 2 | #undef FILE_SIZE #define FILE_SIZE 42 |
دستور فوق FILE_SIZE تعریف شده را حذف می کند و سپس آن را با مقدار جدید یعنی 42 تنظیم می کند.
1 2 3 | #ifndef MESSAGE #define MESSAGE "You wish!" #endif |
دستور فوق بررسی می کند که آیا MESSAGE تعریف شده است یا خیر. در صورتی که تعریف نشده باشد، آن را تعریف می کند.
1 2 3 | #ifdef DEBUG /* Your debugging statements here */ #endif |
اگر DEBUG تعریف شده باشد، دستورات موجود در بلوک #ifdef و #endif اجرا می شوند.
ماکروهای از پیش تعریف شده
جدول زیر ماکروهای از پیش تعریف شده در زبان برنامه نویسی C را نشان می دهد:
ردیف | توضیحات |
1 | __DATE__ تاریخ جاری در فرمت “MMM DD YYYY” را در خود ذخیره می کند. |
2 | __TIME__ زمان جاری در فرمت “HH: MM: SS” را در خود ذخیره می کند. |
3 | __FILE__ نام فایل جاری را به صورت رشته در خود ذخیره می کند. |
4 | __LINE__ شماره خط جاری را به صورت یک عدد دسیمال در خود ذخیره می کند. |
5 | __STDC__ اگر عمل کامپایل بر اساس استاندارد ANSI صورت گیرد، مقدر یک را در خود ذخیره می کند. |
برای مشاهده عملکر ماکروهای فوق مثال زیر را امتحان کنید:
1 2 3 4 5 6 7 8 | #include <stdio.h> int main() { printf("File :%s\n", __FILE__ ); printf("Date :%s\n", __DATE__ ); printf("Time :%s\n", __TIME__ ); printf("Line :%d\n", __LINE__ ); printf("ANSI :%d\n", __STDC__ ); } |
زمانی که کد بالا کامپایل و اجرا شود، نتیجه زیر را تولید خواهد کرد:
1 2 3 4 5 | File :test.c Date :Jun 2 2012 Time :03:36:24 Line :8 ANSI :1 |
عملگرهای پیش پردازنده
زبان C برای ایجاد ماکروهایی با قابلیت بیشتر، عملگرهای زیر را ارائه می کند.
عملگر ادامه ماکرو (\)
یک ماکرو معمولا در یک خط نوشته می شود، اما ممکن است گاهی اوقات ماکرو ما طولانی شود. در این مواقع می توان از عملگر (\) استفاده کرد. مانند نمونه زیر:
1 2 | #define message_for(a, b) \ printf(#a " and " #b ": We love you!\n") |
عملگر رشته سازی (#)
از این عملگر برای تبدیل پارامتر یک ماکرو به یک رشته استفاده می شود. مثال زیر به خوبی نحوه عملکر این عملگر را نشان می دهد:
1 2 3 4 5 6 7 | #include <stdio.h> #define message_for(a, b) \ printf(#a " and " #b ": We love you!\n") int main(void) { message_for(Carole, Debra); return 0; } |
زمانی که کد بالا کامپایل و اجرا شود، نتیجه زیر را تولید خواهد کرد:
1 | Carole and Debra: We love you! |
عملگر چسباندن token (##)
این عملگر دو token جدا را به یک token واحد تبدیل می کند. به مثال زیر توجه کنید:
1 2 3 4 5 6 7 | #include <stdio.h> #define tokenpaster(n) printf ("token" #n " = %d", token##n) int main(void) { int token34 = 40; tokenpaster(34); return 0; } |
زمانی که کد بالا کامپایل و اجرا شود، نتیجه زیر را تولید خواهد کرد:
1 | token34 = 40 |
خروجی واقعی پیش پردازنده به صورت زیر است:
1 | printf ("token34 = %d", token34); |
عملگر Defined()
عملگر defined در یک عبارت ثابت بررسی می کند که یک شناسه با استفاده از دستور #define تعریف شده است یا نه. اگر تعریف شده باشد، مقدار غیر صفر (true) باز میگرداند و اگر تعریف نشده باشد، مقدار صفر (false) باز میگرداند. مثال زیر نحوه استفاده از این عملگر را نشان می دهد:
1 2 3 4 5 6 7 8 | #include <stdio.h> #if !defined (MESSAGE) #define MESSAGE "You wish!" #endif int main(void) { printf("Here is the message: %s\n", MESSAGE); return 0; } |
زمانی که کد بالا کامپایل و اجرا شود، نتیجه زیر را تولید خواهد کرد:
1 | Here is the message: You wish! |
ماکروهای پارامتریک
یکی از ویژگی های قدرتمند پیش پردازنده، امکان شبیه سازی توابع با استفاده از ماکروهای پارامتریک می باشد. برای نمونه مثال زیر را در نظر بگیرید:
1 2 3 | int square(int x) { return x * x; } |
کد بالا را می توان به این صورت هم نوشت:
1 | #define square(x) ((x) * (x)) |
ماکروهای پارامتریک باید قبل از استفاده شدن، توسط دستور #define تعریف شوند. لیست پارامترها بین پرانتز باز و بسته قرار می گیرد و نباید بین نام ماکرو و پرانتزها فاصله باشد. مثلا:
1 2 3 4 5 6 7 | #include <stdio.h> #define MAX(x,y) ((x) > (y) ? (x) : (y)) int main(void) { printf("Max between 20 and 10 is %d\n", MAX(10, 20)); return 0; } |
زمانی که کد بالا کامپایل و اجرا شود، نتیجه زیر را تولید خواهد کرد:
1 | Max between 20 and 10 is 20 |
هیچ نظری ثبت نشده است