Table of Contents
ماکروها در C یک ویژگی قدرتمند از فاز پیش پردازش هستند که به برنامه نویسان اجازه می دهد تا ثابت ها، اسنیپت های کد خط را تعریف کنند و هنگام استفاده موثر، به طور قابل توجهی قابلیت بازیابی کد و قابلیت نگهداری را افزایش دهند، توسعه دهندگان را قادر می سازد تا تمیزتر، برنامه های انعطاف پذیر تر را بنویسند؛ استفاده نادرست ماکرو می تواند اشکالات ظریف را معرفی کند و کد سخت تر برای کشف این مقاله استاندارد، در حالی که چگونه از روش های ماکرو استفاده می کند.
ماکروها چه هستند؟
ماکروها با استفاده از دستورالعمل تعریف شده و توسط پیش پردازنده C قبل از شروع به کار می شوند، پیش پردازنده جایگزین متن ساده را انجام می دهد: هر رویداد از نام ماکرو در کد منبع با تعریف ماکرو جایگزین می شود (LT 2:2) این جایگزینی صرفا متن است و به دامنه یا نوع بررسی ماکروها احترام نمی گذارد.
#define PI 3.14159 // object-like macro
#define SQUARE(x) ((x)*(x)) // function-like macro
درک این مرحله پیش پردازش بسیار مهم است زیرا ماکروها قوانین مشابهی را به عنوان توابع یا متغیرهای دنبال نمی کنند، آنها به صورت خط گسترش می یابند، که مزایای عملکردی را به آنها می دهد، اما همچنین چالش های منحصر به فرد را معرفی می کند.
مزایای ماکرو برای قابلیت بازسازی و نگهداری کد
هنگامی که به طور فکری اعمال می شود، ماکروها مزایای مشخصی در پایه های کد حساس بزرگ یا عملکردی ارائه می دهند:
- قابلیت بازگشت کد : تعریف یک محاسبه مشترک یا قطعه یک بار و استفاده از آن در سراسر برنامه.
- [[۱] [۱۰] [۱] [۱۰] [۱] [۱]] [۱]] [۱] [۳] [۱] [۱] [۱]] [۳] [۱] [۱] [۱۰] [۱]] [۱] [۱] [۱] [۳] [۳] [۳] [۳] [۳] [۳] نام های معنی دار به آنها بدهید و پارامترهای تنظیم کننده را بهبود می بخشد.
- سودهای مقیاسی ؛ ماکروهای تابع مانند از بالای یک تماس تابع اجتناب می کنند، برای عملیات های کوچک و اغلب استفاده شده (به عنوان مثال، من / حداکثر مربع)، ماکروها می توانند سریعتر از حتی توابع خط در برخی از کامپایلرهایی که در آن درلینینگ تضمین نمی شود.
- [[۱] [۱۰] [۱]: ماکروها با [FLT:] [۱] [۱] [۱] کار می کنند، با و برای شامل یا حذف کد بر اساس شرایط کامپایل شده ضروری است.
- پیکربندی تقویت شده : با تعریف ماکروها با مقادیر مختلف در یک هدر، شما می توانید رفتار یک کد پایه کامل را بدون لمس فایل های پیاده سازی تطبیق دهید.
نوشتن ماکروهای قوی: بهترین تمرین ها
انعطاف پذیری ماکروها نیز خطر آنهاست.یک ماکرو ضعیف نوشته شده می تواند باعث رفتارهای غیرمنتظره ای شود که ردیابی آن ها دشوار است.
همیشه پارامترهای والدین و کل بیان
از آنجا که ماکروها جایگزین های متنی هستند، اولویت اپراتور می تواند آنها را بشکند، ماکرو مانند گسترش خواهد یافت برای (که برابر 11، نه 25) تعمیر است که هر پارامتر در پرانتزها را بسته و کل بیان را بسته بندی می کند:
#define SQUARE(x) ((x) * (x)) // now SQUARE(3+2) works correctly
اجتناب از ارزیابی های متعدد از Arguments
استدلال های ماکرو به عنوان جایگزین می شوند اگر استدلال دارای عوارض جانبی (به عنوان مثال، [FLT 11] باشد، ممکن است بیش از یک بار ارزیابی شود.
#define MAX(a,b) ((a) > (b) ? (a) : (b))
int x = 5;
int max = MAX(x++, 10); // expands to ((x++) > (10) ? (x++) : (10)) // x incremented twice!
برای جلوگیری از این، توابع خط را ترجیح دهید یا از قراردادهای نام گذاری دقیق برای هشدار به کاربران استفاده کنید، اگر باید از ماکرو استفاده کنید، سند که استدلال ها نباید حاوی عوارض جانبی باشد.
استفاده از Highcase برای نام های ماکرو
در این نامه، ماکروها در حروف بالا نوشته شده اند (به عنوان مثال، [FLT13]، ، این باعث می شود آنها از متغیرهای و توابع، کاهش احتمال برخورد تصادفی.
پایان دادن به ماکرو با بلوک های چند دولتی
هنگامی که یک ماکرو را تعریف می کنیم که شامل چندین جمله است، آنها را در یک حلقه (FLT:15) قرار دهید، این تضمین می کند که ماکرو در تمام زمینه ها به درستی رفتار می کند (به عنوان مثال، پس از یک (FLT:16 بدون بریس):
#define LOG_ERROR(msg) do { \
fprintf(stderr, "Error: %s\n", msg); \
exit(1); \
} while (0)
دانلود بازی Supers Thorough
ماکروها فاقد ماهیت خود-انجام وظایف هستند.همیشه نظراتی را که استدلال ها، رفتار مورد انتظار و هر گونه محدودیت را توصیف می کنند، اضافه کنید.
تکنیک های پیشرفته ماکرو
پیش پردازنده C اپراتورهای قدرتمندی را ارائه می دهد که فراتر از جایگزینی ساده هستند. تسلط بر این می تواند ماکروهای شما را حتی انعطاف پذیرتر کند.
و با استفاده از [[FLT 18]]
اپراتور تبدیل یک بحث ماکرو به یک رشته لفظی است که این برای اشکال زدایی یا ورود مفید است:
#define PRINT_VAR(x) printf(#x " = %d\n", x)
int value = 42;
PRINT_VAR(value); // prints: value = 42
قبلی: با استفاده از [[FLT 21]]
اپراتور دو توکن را به یک توکن واحد متصل می کند، این به شما اجازه می دهد تا شناسه ها را به صورت پویا در زمان کامپایل شده ایجاد کنید:
#define CREATE_VAR(prefix, index) prefix ## index
int CREATE_VAR(arr, 0) = 10; // becomes int arr0 = 10;
گذشته سازی توکن به طور گسترده ای در ماکروهای X و برای تولید الگوهای تکراری کد استفاده می شود.
ماکروهای متنوع (C99)
ماکروهای variadic معرفی شده در C99، تعداد متغیری از استدلال ها را با استفاده از می پذیرند.این امر باعث می شود که ورود انعطاف پذیر و ماکروهای اشکال زدایی شود:
#define DEBUG_PRINT(fmt, ...) \
fprintf(stderr, "DEBUG: " fmt, __VA_ARGS__)
DEBUG_PRINT("x = %d, y = %d", x, y);
در C11 و بعد، می توانید از [FLT 26] برای رسیدگی به کاما در استدلال های خالی، بهبود قابلیت حمل و نقل استفاده کنید.
قرص های معمول و چگونگی اجتناب از آن
حتی توسعه دهندگان C با اشکالات مرتبط با ماکرو مواجه می شوند. تشخیص این مشکلات در ابتدا مانع سردرد می شود.
- (فَلَهُمَهُمَهُمَهُمَهُمَهُمَهُمَهُمَهُمَهُمَهُوا مَنَهُمَهُمَهُوا مَهُمَهُمَهُمَهُمَهُمَهُمَهُوا مَهُمَهُمَهُمْهُوا مَهُوَهُمْهُمْهُوا مَهُمْهُمْهُمَهُمَهُمَهُمْهُمْهُوَهُمْهُوَهُوَهُمْهُوَهُمَهُوا مَهُمَهُمَهُمَهُوَهُوا مَهُمَهُمَهُوَهُوَهُمَهُوَهُوَهُمَهُوَهُوَهُوَهُ
- [[۱] [۱۰] [۱۰] [۱۰] [۱] [۱۰] [۱]] [۱۰] [۱] [۱] [۱۰] [۱]] [۱۰] [۱] [۱۰] [۱] [۱۰] [۱] [۱۰] [۱] [۱] [۱۰] [۱] [۱] [۱] [۶] [۸] [۱] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۶] [۸] [۸] [۶] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [۸] [
- ماکروهای دارای عملکرد [FLT 1]: اگر ماکرو را با همان نام به عنوان یک تابع کتابخانه استاندارد تعریف کنید، می تواند به آرامی آن را نادیده بگیرد.
- داروهای اولیه غیر قابل پیش فرض استفاده می شوند؛ ماکروهای مانند اشیاء به عنوان ثابت استفاده می شوند، اما آنها نمی توانند در عبارات ثابت استفاده شوند، تنها در صورتی که گسترش خود یک بیان ثابت است.
- سختی کشیدن ؛ ماکروها قبل از اینکه کامپایلر آنها را ببیند، گسترش یافته اند، بنابراین پیام های خطا به کد گسترش یافته اشاره می کنند، نه نام ماکرو با استفاده از پرچم FLT:28 با GCC یا Clang (به عنوان مثال، [FLT 29] نشان می دهد خروجی پیش پردازش شده است تا مسائل را ردیابی کند.
جایگزین های ماکرو: توابع، enum و Inline
C مدرن گزینه های امن تری را فراهم می کند که اغلب نیاز به ماکرو را از بین می برد:
- [[۱] [۱۰] [۱۰] [۱۰] [۱۰] [[۳]] [[۳]] [[۳]] [۱] [۱]] [۳]] [۳] [۱] [۱۰]] [۳] [۱۰] [۱]] [۳] [۳]] [۳] [۳] [۳] [۳]] [۳]] [و [۳]] [۳]]] [۳]] [در [در صورت استفاده از اندازه های ثابت و [در همهٔ [و [در [در اندازهٔ [در برابر [و [و [در برابر [در برابر [و [در] متغیر] استفاده می شود] استفاده می کنند] ثابت [در [و [در [در [در [در [در [در [و [و [و [در] [و [و [در] [در] [در] [در] [در همهٔ] [در] [در] [در] [در [در] [در] [در] [در] [در [در] [در [در [در] [در] [در] [در] [در] [در] ثابت [در [در [در
- [FLT: برای مجموعه ای از ثابت های صحیح مرتبط، enums نوع امن و به طور خودکار اختصاص ارزش ها است.
- عملکرد خط : معرفی در C99، توابع عملکرد ماکرو با ایمنی کامل نوع، پشتیبانی از اشکال زدایی و اجتناب از مسائل جانبی را فراهم می کند.
static inline int square(int x) {
return x * x;
}
استفاده از توابع خط هر زمان که شما نیاز به یک ماکرو مانند تابع دارید که دقیقا یک بار استدلال را ارزیابی می کند.تنها مورد استفاده باقی مانده برای ماکروهای تابع مانند زمانی است که شما نیاز به کار بر روی انواع (به عنوان مثال، نوع در GNU C) یا نیاز به توانایی باز کردن یک محدوده جدید (مانند اصطلاح do-but).
مثال های واقعی جهانی: Debugging و Configuration
ماکروها در سناریوهای مشروط برتری دارند، در اینجا دو برنامه کاربردی عملی وجود دارد:
Debug با وارد کردن با Compile-Time Control
#ifdef DEBUG
#define LOG(fmt, ...) fprintf(stderr, "[DEBUG] " fmt, ##__VA_ARGS__)
#else
#define LOG(fmt, ...) /* no-op */
#endif
این امر تنها زمانی است که با [FLT 38] وارد می شود و ماکرو خالی باعث می شود که صفر در خروجی ایجاد شود. [FLT 39] قبل از یک پسوند گنو است که کاما را حذف می کند، زمانی که هیچ گونه استدلالی ارائه نمی شود (همچنین در C20 با پشتیبانی می شود.
سیستم عامل-Specific Code
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM "Windows"
#elif defined(__linux__)
#define PLATFORM "Linux"
#else
#define PLATFORM "Unknown"
#endif
این الگو وابستگی های پلتفرم را بدون تکرار کل توابع جدا می کند.همراه با نگهبانان (FLT:43)، هدرها را تمیز و قابل نگهداری نگه می دارد.
نتیجه گیری
ماکروها یک ابزار ضروری در C برای قابلیت استفاده و نگهداری کد باقی می مانند، به ویژه در زمینه های عملکردی بحرانی یا جاسازی شده که در آن هر چرخه به درستی مورد استفاده قرار می گیرد – با استفاده از مناسب والدین، عوارض جانبی محدود و نامگذاری مناسب – آنها اغلب تکرار و پیکربندی لایه برداری را کاهش می دهند.با این حال، روند در C مدرن جایگزین ماکرو مانند عملکرد در توابع خط یا عمومی (معمولا برای به دست آوردن قابلیت استفاده از نوع ماکرو و 5.4) است.
با متعادل کردن قدرت ماکرو سنتی با این گزینه های امن تر، می توانید کد C را بنویسید که هم کارآمد و هم قوی باشد، برای مطالعه بیشتر، با منوی پیش پردازنده (FLT:1) و C] در ماکروها مشورت کنید. درک مشکلات ماکرو در جزئیات نیز در این [FLT4] جاسازی شده است.