پنجشنبه، اردیبهشت ۰۶، ۱۳۸۶

پیش‌پردازنده در C++

۱.
در
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 را درج کنید.