۱.
در C/C++
عباراتی وجود
دارند که
کامپایل نمیشوند،
بلکه
کامپایلر را
هدایت میکنند.
این دستورات
با کاراکتر
# شروع میشوند.
مثل
#define و
#pragma و
#if و ... به
این عبارات preprocessor
directive میگویند.
۲.
در C/C++ کامپایل هر
فایل دو مرحله
دارد. در یک
مرحله تمام preprocessor
directive ها
خوانده و
جایگذاری میشوند
(به غیر از آنهایی
که سروکارشان
با خود
کامپایلر،
یعنی مرحله
بعد، است) و در
مرحله بعد
فایل حاصل به
یک Object File
کامپایل میشود.
واحدی که
وظیفه مرحله
اول را بر
عهده دارد preprocessor نام
دارد و علت
نامگذاری آن هم
از همین نکته
نشئت گرفته: واحدی
که عباراتی را
قبل از عمل
کامپایل اصلی پردازش
میکند.
۳.
برای اینکه
منظور از
جایگذاری preprocessor
directive ها
را متوجه شویم
به چند مثال
توجه کنید. مثلا
در عبارت
#include "somefile.h" |
واحد preprocessor کل
این خط را حذف
میکند و
محتویات
"somefile.h" را به
جایش قرار میدهد
و فایل نهایی حاصل
را به
کامپایلر میفرستد
و یا در عبارت
#define MSG "Hello" |
preprocessor کلیه توکنهایی
را که مساوی
MSG باشند
را با رشته
"Hello" جایگزین
میکند.
۴.
برای مشاهده
خروجی preprocessor، تنها و
بدون کامپایل source برنامه،
هنگام
استفاده از gcc
از دستور زیر
استفاده کنید.
$ g++ -E src.cpp -o src-no-prep.cpp [you can use gcc instead of g++ too] |
و هنگام
استفاده از
کامپایلر Microsoft Visual
C++ از
دستور زیر
استفاده کنید.
$ cl.exe src.cpp /E > src-no-prep.cpp |
۵.
برای مثال
برنامه کوتاه
زیر را در نظر
بگیرید:
C++ |
---|
#include <iostream> using namespace std; #define MSG "Hello" int main() { cout << MSG << endl; return 0; } |
حالا فایلهای
خروجی preprocessor را باز
کنید. جالب
است بدانید که
gcc
فایل مبدا ۱۰
خطی شما را به
یک فایل غولپیکر
۲۳۸۵۹ خطی
تبدیل کرده. خروجی
Visual C++
هم یک فایل ۴۵۰۴۱
خطی است (که
البته تعداد
زیادی از خطهای
آن خالی است).
تنها حدود ۱۰ خط
آخر این فایلها
را شما نوشتهاید.
این فایلها
بدون هیچ
مشکلی قابل
کامپایل کردن
هستند.
۶.
هنوز فایلهای
خروجی تعدادی preprocessor
directive
دارند که از
بین نرفتهاند.
اگر دقت کنید
این directive ها همگی یا
#line هستند یا
#pragma. کامپایلر
عبارت
#line را
برای تولید
خطا و
راهنمایی
برنامهنویس
لازم دارد. همچنین
#pragma هم یک
سری option
ها را برای کامپایلر
مشخص میکند.
۷.
حالا شاید
واضحتر شده
باشد که چرا
ترتیب نوشتن preprocessor
directive ها
مهم است.
پ.ن.
۱. خیلی جاها به این عبارات به اشتباه preprocessor گفته میشود. در حالی که preprocessor یک قسمت از کامپایلر است. نام صحیحتر این عبارات preprocessor directive میباشد.
5 نظر:
من یک چیزهایی درباره این دستورهای پیش پردازنده می دانم، اما راستش منظورت درباره اهمیت ترتیب آنها را درست متوجه نمی شوم، منظورت چیزی مثل استفاده از
ifndef
است؟
سلام پاسپارتو جان. چیزهایی که بیشترین تاثیر رو روی ترتیب دستورات پیشپردازش میزارن همون ماکروها و
ifdef و ifndef
است. مثلا دستور
assert
یک شرط رو چک میکنه و اگه برقرار نبود یک استثنا پرتاب میکنه. این دستور داخل
<assert.h>
تعریف شده و تعریفش شبیه اینه.
#ifndef NDEBUG
if(!condition)
throw some_exception();
#endif
این یعنی موقعی که کار دیباگ تموم شده با تعریف
NDEBUG
تمام دستورات
assert
محو میشن و تو محصول نهایی استثنا بی استثنا. حالا فرض کنیم به اشتباه بنویسیم:
#include <assert.h>
#define NDEBUG
هیچ دستور
assert
ای محو نمیشه. اما برعکس اگه بنویسیم:
#define NDEBUG
#include <assert.h>
همهشون میرن پی کارشون. همچنین هر ترتیب برای
include
یک نتیجه رو نمیده و حتی گاهی یه ترتیب خاص خطا ایجاد میکنه که فقط با عوض کردن ترتیب اون خطا از بین میره.
سلام
ممنون سینا جان
این نکته را درباره
assert
نمی دانستم.
سلام
من میخواستم در مورد assert بیشتر بدونم .
اینکه assert جیه؟ معایبش چیه؟ مزیتش چیه؟
ممنون میشم اگه راهنماییم کنی.
assert یک شرط را چک میکند، و اگر شرط برقرار نبود، exception میاندازد، با توضیح کامل که اشکال از کجا آمده. هنگامی که برنامه را بصورت release کامپایل میکنید، دستورات assert همگی از بین میروند و اجرا نمیشوند. بنابراین کاربرد assert در تست کردن حین برنامهنویسی و توسعه است.
مثلاً اگر انتظار دارید که همواره نتیجهی یک محاسبه مثبت باشد، وگرنه یک جای کار ایراد دارد بنویسید:
assert(result > 0); // s
هر وقت این خط exception داد، اون وقت شما متوجه میشید که یه جای کار ایراد داره.
ارسال یک نظر
جهت نمایش صحیح آدرس سایتتان، حتما قبل از آدرس //:http را درج کنید.