ماکروها
همانطور که گفته شد با راهنمای define# يک شناسه را می توان به يک ثابت نسبت داد تا يک ثابت سمبليک شکل بگيرد. از راهنمای define# برای مربوط کردن شناسه های معنی دار به عباراتی که زياد استفاده می شوند هم بکار می رود. وقتی يک شناسه به يک عبارت يا جمله ربط داده می شود ماکرو (macro) ناميده می شود.
شکل کلی تعريف ماکرو به صورت زير است:
#define MACRO_NAME(arg1, arg2, ...) [code to expand to]
arg1، arg2 و ... آرگومان های ماکرو هستند که تعداد آنها اختياری است.
مثال. ماکرو افزايش عدد.
#define INCREMENT(x) ((x)++)
مثال. ماکرو مربع عدد.
#define SquareOf(x) ((x)*(x))
double yout,xin=3;
yout = SquareOf(xin);
ماکرو می تواند چندخطی باشد برای اتصال خطوط در انتهای هر خط بايد علامت قرار بگيرد. خط آخر نيازی به علامت ندارد.
مثال. ماکرو جابه جا کردن دو مقدار.
#define SWAP(a, b) {
a ^= b;
b ^= a;
a ^= b;
}
وقتی پيش پردازنده با نام ماکرو در برنامه مواجه می شود آن را يک فراخوانی به ماکرو تلقی می کند و يک کپی از بدنه ماکرو را جايگزين نام ماکرو می کند. اگر ماکرو دارای پارامترهائی باشد، آرگومان هائی که بدنبال نام ماکرو قرار دارند جايگزين آن ها در بدنه ماکرو می شوند.
در عمل دو نوع ماکرو وجود دارد: شیء گونه که پارامتری ندارد و تابع گونه که می تواند آرگومان هائی را بپذيرد و بسيار شبيه فراخوانی تابع می ماند.
يک ماکرو را می توان دوباره با همان مقدار قبلی تعريف کرد ولی تعريف مجدد ماکرو با مقدار جديد ممکن نيست. مگر اينکه تعريف قبلی را حذف کنيد. راهنمای undef# برای حذف تعريف يک ماکرو است.
چون ماکرو سربار فراخوانی تابع را ندارد سريع تر از تابع عمل می کند. اما بخاطر داشته باشيد فراخوانی ماکرو تنها يک جايگزينی عبارت است و کامپايلر آن را بلافاصله تفسير نمی کند بنابراين کاری در ارتباط با الويت عملگرها، سازگاری نوع، قواعد انتساب يا ارجاع و موارد ديگر ندارد. در نتيجه مخاطراتی را بدنبال خواهد داشت که به برخی از آنها در ادامه اشاره می شود. بنابراين بهتر است با احتياط تعريف شود يا اصلا استفاده نشود.
الويت عبارت
يک راه برای اطمينان از اينکه الويت عبارت در ماکرو حفظ می شود اين است که آرگومان های ماکرو را درون پرانتز قرار دهيد.
مثال. اگر ماکرو به صورت زير تعريف و استفاده شده باشد انتظار داريد مقدار 30 به متغير z اختصاص داده شود درحاليکه مقدار 13 را می گيرد.
#define MULT(x, y) x * y
int z = MULT(3 + 2, 4 + 2);
زيرا وقتی بدنه ماکرو جايگزين می شود به صورت زير در می آيد.
int z = 3 + 2 * 4 + 2;
برای حل اين مشکل بهتر است ماکرو به صورت زير نوشته شود.
#define MULT(x, y) ((x) * (y))
که به صورت زير جايگزين خواهد شد.
int z = (3 + 2) * (4 + 2)
ماکروهای چند دستوری
ماکروهائی که مشابه تابع مقداری را محاسبه و برمی گردانند expression macro ناميده می شوند. و ماکرو می تواند به جای اينکه مقداری را محاسبه کند دارای چند دستور باشد که آنها را action macro می نامند.
بهتر است بدنه ماکروهای چنددستوری را درون علائم {} محصور کنيد تا از بروز مشکل جلوگيری کنيد.
مثال. وقتی ماکرو فراخوانی شود تنها اولين دستور آن a^=b; درون شرط قرار می گيرد و دو دستور ديگر همواره اجرا خواهند شد.
#define SWAP(a, b) a ^= b; b ^= a; a ^= b;
int x = 10;
int y = 5;
SWAP(x, y); // works OK
// What happens now?
if(x < 0)
SWAP(x, y);
بهتر است ماکرو فوق به صورت زير تعريف شود:
#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while ( 0 )
نکته. قرار دادن کل بدنه ماکرو درون پرانتز زمانی که ماکرو مقداری را برنمی گرداند الزامی نيست.
نکته. در ++C از ماکروها تا حد ممکن استفاده نمی شود چون در اکثر موارد نيازی به آنها ديده نمی شود. بيشتر از عبارت const برای تعريف ثابت و توابع درون خطی به ماکروها ترجيح داده می شوند زيرا مشکلات ماکروها را ندارند.
مثال. تابع درون خطی محاسبه مربع عدد.
void SquareOf(int x) {return x*x;}
نکاتی درباره نوشتن ماکرو
1- استفاده از يک قرارداد نامگذاری برای اسامی ماکرو تشخيص آنها را در برنامه ساده تر می کند. برای مثال نام همه ماکروها با حرف m شروع شود.
2- درنظر داشته باشيد چه نوع ماکروئی می نويسيد عبارتی يا چنددستوری.
3- کل بدنه ماکرو را در پرانتز قرار دهيد.
4- در بدنه ماکرو آرگومان ها را درون پرانتز قرار دهيد.
5- در ماکروهایچنددستوری هر دستور را به علامت سميکولن ختم کنيد و کل بدنه ماکرو را درون آکولاد قرار دهيد.
6- کليه ماکروها را در يک فايل هدر قرار دهيد.
ماکروهای تعريف شده
تعدادی ماکرو در ++C تعريف شده است که می توانيد از آنها استفاده کنيد. کامپايلر قادر به شناسائی ماکروهای پيش تعريف شده است. اين ماکروها آرگومانی نمی گيرند و مجدد قابل تعريف نيستند.
بعضی از آنها که توسط ANSI تعريف شده است در جدول زير آمده است: