ماکروهای کاربردی در امبدد C | نوشتن ماکرو Swap و بررسی کاراکتر

قسمت 31
embedded C شاخص 31
مشاهده سایر جلسات آموزش
166 بازدید
۱۴۰۵-۰۲-۱۴
7 دقیقه
  • نویسنده: Alireza Abbasi
  • درباره نویسنده: ---

کامپایل شرطی

کامپایل شرطی به ما امکان تغییر محتوای کد در زمان کامپایل را می‌دهد. استفاده کلاسیک از این ویژگی، داشتن نسخه‌های دیباگ و تولید برنامه است. دستورالعمل ifdef / #endif#کد بین دو دستورالعمل را کامپایل می‌کند اگر یک نماد تعریف شده باشد. در ادامه مثالی آمده است:

کمپایل مشروط به ما امکان می‌دهد تا محتویات کد خود را در زمان کامپایل تغییر دهیم. استفاده کلاسیک از این ویژگی، داشتن نسخه دیباگ و نسخه نهایی (production) از یک برنامه است.

عبارت دستوری ifdef / #endif#کد بین این دو دستور را کامپایل می‌کند، در صورتی که یک نماد (سمبل) تعریف شده باشد. در اینجا یک مثال آورده شده است:

به طور دقیق، کامنت  DEBUG//مورد نیاز نیست، اما حتما آن را لحاظ کنید زیرا جفت کردن عبارات ifdef/#endif#به اندازه کافی دشوار است.

اگر برنامه شما به شکل زیر باشد:

در این صورت خروجی پیش‌پردازنده به صورت زیر خواهد بود:

از طرف دیگر، اگر برنامه شما به شکل زیر باشد:

در این حالت، هیچ خروجی برای printf تولید نمی‌شود، زیرا نماد DEBUG تعریف نشده است.

پس خروجی پیش‌پردازنده به صورت زیر خواهد بود:

از آنجایی که DEBUG تعریف نشده است، هیچ کدی تولید نمی‌شود.

تمام دستورات ifdef#باعث می‌شوند برنامه ظاهر زشتی پیدا کند و این برای ما کمی ناخوشایند است. کد زیر را در نظر بگیرید:

می‌توانیم با کد بسیار کمتر به همان نتیجه برسیم:

شاید برای شما مفید باشد:
بررسی سخت‌افزار و اتصال ENC28J60

توجه کنید که ما از دستورelse#در پیش‌پردازنده برای معکوس کردن مفهوم if#استفاده کرده‌ایم. اگر DEBUG تعریف شده باشد، فراخوانی‌های debug با فراخوانی‌های printf جایگزین می‌شوند؛ در غیر این صورت، آنها با فضای خالی جایگزین می‌شوند. در این مورد، به ترفند do/while نیاز نداریم زیرا ماکرو کد حاوی یک فراخوانی تابع (بدون سمی‌کالن) است.

دستور دیگر، ifndef# است که در صورتی که یک نماد تعریف نشده باشد، درست است و در غیر این صورت به همان روشی که دستور ifdef#استفاده می‌شود.

نمادها را از کجا تعریف کنیم؟

ما می‌توانیم نمادها را به سه روش تعریف کنیم:

  • داخل برنامه با دستور define#
  • از طریق خط فرمان
  • از پیش تعریف شده در پیش پردازنده

ما قبلاً نمادهای تعریف‌شده داخل برنامه را توضیح دادیم، پس بیایید به دو گزینه دیگر نگاه کنیم.

نمادهای خط فرمان

برای تعریف یک نماد روی خط فرمان، از گزینه D- استفاده کنید:

آرگومان DDEBUG- نماد DEBUG را تعریف می‌کند تا پیش‌‌پردازنده بتواند از آن استفاده کند. به عبارتی دیگر، این دستور معادل نوشتن define DEBUG 1 # در ابتدای کد است، قبل از اینکه برنامه اصلی شروع به کامپایل شدن کند. ما از این نماد در کد قبلی برای مدیریت این موضوع که آیا عبارات debug در خروجی نهایی گنجانده شوند یا نه، استفاده کردیم.

علاوه بر نمادهایی که ما به صورت دستی به کامند کامپایل اضافه می‌کنیم، نرم‌افزار STM32 Workbench یک فایل Makefile برای کامپایل برنامه‌ای ایجاد می‌کند که تعدادی نماد را در خط فرمان تعریف می‌کند. مهم‌ترین نماد با گزینه DSTM32F030x8- تعریف می‌شود. فایل CMSIS/device/stm32f0xx.h از نماد STM32F030x8 برای دربرگرفتن فایل‌های خاص برد استفاده می‌کند:

فریمور STM32 از تعدادی برد پشتیبانی می‌کند که فقط یکی از آنها NUCLEO-F030R8 است. هر تراشه مجموعه‌ای متفاوت از دستگاه‌های ورودی/خروجی دارد که در مکان‌های مختلفی قرار گرفته‌اند. شما لازم نیست نگران محل قرارگیری آن‌ها باشید، زیرا فریمور با استفاده از کد قبلی مکان مناسب را پیدا می‌کند. این کد می‌گوید، “اگر من یک STM32F030x6 هستم، فایل هدر مربوط به آن برد را دربربگیر؛ اگر یک STM32F030x8 هستم، فایل هدر مربوط به آن برد را دربربگیر” و به همین ترتیب.

دستورهای استفاده شده if# و elif# هستند. دستور if# بررسی می‌کند که آیا عبارتی در ادامه آمده درست است یا نه (در این مورد، اینکه آیا STM32F030x6 تعریف شده است). اگر درست باشد، کد پس از آن کامپایل می‌شود. elif# ترکیبی از else# و if# است که می‌گوید اگر عبارت درست نباشد، یک عبارت دیگر را بررسی کن. دستور دیگر، defined، در صورتی که نماد تعریف شده باشد، مقدار درست برمی‌گرداند.

نمادهای پیش‌تعریف‌شده

در نهایت، خود پیش‌‌پردازنده تعدادی نماد را تعریف می‌کند، مانند __VERSION__ (برای مشخص کردن نسخه کامپایلر) و __linux (در سیستم‌های لینوکس). برای اینکه ببینید چه نمادهایی در سیستم شما از پیش تعریف شده‌اند، از دستور زیر استفاده کنید:

نماد __cplusplus تنها در صورتی تعریف می‌شود که شما یک برنامه C++ را کامپایل کنید. اغلب اوقات، کدهایی شبیه به این را در فایل‌ها مشاهده خواهید کرد:

این کد بخشی از مکالمه و هماهنگی‌ای است که C++ برای استفاده از برنامه‌های C به آن نیاز دارد. فعلاً می‌توانید آن را نادیده بگیرید.

 

فایل‌های الحاقی

دستور include #به پیش‌‌پردازنده می‌گوید کل یک فایل را وارد کند، گویی بخشی از فایل اصلی است. دو فرم برای این دستور وجود دارد:

فرم اول فایل‌های هدر سیستم (فایل‌هایی که با کامپایلر یا کتابخانه‌های سیستمی که استفاده می‌کنید، همراه هستند) را وارد می‌کند. فرم دوم فایل‌هایی را که خودتان ایجاد کرده‌اید، وارد می‌کند.

یکی از مشکلات فایل‌های هدر این است که ممکن است دو بار وارد شوند. اگر این اتفاق بیفتد، با تعداد زیادی نماد تکراری تعریف‌شده و مشکلات دیگری روبرو خواهید شد. راه‌حل این مشکل افزودن یک نگهبان (sentinel) با استفاده از الگوی طراحی زیر است:

شاید برای شما مفید باشد:
خواندن چندین ورودی آنالوگ و اندازه‌گیری ولتاژ در آردوینو

در بار اول که به این کد برخورد می‌کنیم، نماد __FILE_NAME_H__ (نگهبان) تعریف نشده است. بنابراین، کل فایل هدر در برنامه گنجانده می‌شود. این همان چیزی است که می‌خواهیم، چون فقط یک بار به این فایل نیاز داریم.

در  دفعات بعدی که پیش‌‌پردازنده به این کد می‌رسد، نماد __FILE_NAME_H__ قبلاً تعریف شده است. دستور ifndef #باعث می‌شود که کد بعد از آن تا رسیدن به endif #در انتهای فایل، دیگر شامل نشود. بنابراین، اگرچه فایل هدر دو بار در لیست include #قرار گرفته باشد، محتوای آن فقط یک بار در خروجی نهایی ظاهر می‌شود.

سایر دستورات پیش‌‌پردازنده

علاوه بر دستورات اصلی، چند دستور پیش‌‌پردازنده کم‌اهمیت‌تر نیز وجود دارد که مفید هستند، مانند warning، #error #و pragma#.

  • warning#

دستور warning #در صورت مشاهده شدن، یک هشدار کامپایلر را نمایش می‌دهد:

در این مثال، اگر نماد PROCESSOR تعریف نشده باشد، پیش‌پردازنده یک هشدار با متن “No processor — taking default” نمایش می‌دهد و سپس مقدار پیش‌فرض DEFAULT_PROCESSOR را برای این نماد در نظر می‌گیرد.

  • error#

دستور مرتبط، error#، یک خطا صادر می‌کند و کامپایل شدن برنامه شما را متوقف می‌کند:

اگر نماد RELEASE_VERSION تعریف نشده باشد، این دستور خطایی با متن “No release version defined. It must be defined” صادر می‌کند و کامپایلر دیگر به کامپایل کد ادامه نمی‌دهد.

  • pragma#

دستور #pragma برای تعریف کنترل‌های وابسته به کامپایلر استفاده می‌شود. در اینجا یک مثال آورده شده است:

این کد برای کامپایلر GCC نوشته شده است. دستور pragma# هشدارهای مربوط به نبودن prototype (اعلامیه اولیه توابع) را خاموش می‌کند، سپس فایل هدر باگ‌دار buggy.h را در بر می‌گیرد و در نهایت، دوباره هشدارها را روشن می‌کند.

ترفندهای پیش‌‌پردازنده

پیش‌‌پردازنده یک پردازشگر ماکرو ساده است و در نتیجه، همانطور که قبلاً توضیح داده شد، برای اینکه به مشکل برنخوریم، مجبور بودیم مجموعه‌ای از قواعد سبک را اتخاذ کنیم. قدرت پیش‌‌پردازنده همچنین به ما اجازه می‌دهد تا برای آسان‌تر کردن کارمان، چند ترفند جالب انجام دهیم. یکی از آن‌ها ترفند enum است که در فصل ۸ در مورد آن بحث کردیم. در این بخش، به کامنت کردن کد نگاهی خواهیم انداخت.

گاهی اوقات، برای تست برنامه نیاز داریم بخشی از کد را غیرفعال کنیم. یک راه برای انجام این کار، کامنت کردن کد است. برای مثال، فرض کنید فرآیند حسابرسی باگ دارد؛ می‌توانیم آن را غیرفعال کنیم تا گروه حسابرسی کار خود را به درستی انجام دهند.

در اینجا کد اصلی آورده شده است:

و در اینجا کدی وجود دارد که حسابرسی از آن حذف شده است:

شاید برای شما مفید باشد:
رجیسترهای پورت XMEGA

هر خطی که می‌خواستیم حذف شود، اکنون با نشانگر کامنت (//) شروع می‌شود.

با این حال، کامنت کردن تک تک خطوط کار پر زحمتی است. در عوض، می‌توانیم از کامپایل مشروط برای حذف کد استفاده کنیم. تنها کاری که باید انجام دهیم احاطه کردن کد با عبارات ifdef UNDEF #و endif // UNDEF #است، به این صورت:

کد داخل بلاک ifdef/#endif #فقط در صورتی کامپایل می‌شود که نماد UNDEF تعریف شده باشد. تعریف کردن این نماد کار عاقلانه‌ای نیست چون معنای خاصی ندارد. استفاده از if 0 / #endif #نیز به همین نتیجه می‌رسد، با این مزیت که به عقل برنامه‌نویس‌های دیگر وابسته نیست.

خلاصه

پیش‌‌پردازنده C یک ویرایشگر متن خودکار ساده اما قدرتمند است. استفاده صحیح از آن می‌تواند برنامه‌نویسی را به شدت آسان‌تر کند. این ابزار به شما امکان می‌دهد ماکروهای عددی ساده و همچنین ماکروهای کد کوچک تعریف کنید. (البته تعریف ماکروهای کد بزرگ هم ممکن است، اما بهتر است این کار را انجام ندهید.)

یکی از مهم‌ترین ویژگی‌های آن، دستور include #است که به اشتراک‌گذاری رابط‌ها بین ماژول‌ها کمک می‌کند. همچنین، قابلیت‌های ifdef #به شما اجازه می‌دهند تا با استفاده از کامپایل مشروط، یک برنامه بنویسید که شخصیت‌های مختلفی داشته باشد.

با این حال، باید به خاطر داشته باشید که پیش‌‌پردازنده، ترکیب (syntax) زبان C را درک نمی‌کند. در نتیجه، برای استفاده مؤثر از این سیستم، باید چندین قانون سبک و الگوی برنامه‌نویسی را به خاطر بسپارید.

با وجود تمام محدودیت‌ها و پیچیدگی‌هایش، پیش‌‌پردازنده می‌تواند ابزاری قدرتمند برای ایجاد برنامه‌های C باشد.

مسائل برنامه‌نویسی

یک ماکرو برای جابه‌جایی دو عدد صحیح بنویسید.

  • پیشرفته: یک ماکرو برای جابه‌جایی دو عدد از هر نوع (داده) بنویسید. (قبل از انجام این کار، مستندات کلیدواژه typeof کامپایلر GCC را مطالعه کنید.)
  • یک ماکرو به نام islower(x) ایجاد کنید که اگر x یک حرف کوچک باشد، مقدار درست برگرداند.
  • فوق‌العاده پیشرفته: بفهمید برنامه‌ی zsmall.c چگونه کار می‌کند . این برنامه برنده‌ی مسابقه‌ی کد مبهم C شده است (جایزه‌ی بهترین سوءاستفاده از پیش‌‌پردازنده را دریافت کرده است). این برنامه تنها یک لیست از اعداد اول را چاپ می‌کند، اما تمام محاسبات و حلقه‌ها با استفاده از پیش‌‌پردازنده انجام می‌شوند.
اطلاعات
166
0
0
اشتراک و حمایت
جلسات دیگر
آموزش

آشنایی با پیش‌پردازنده C و ماکروها: از ‎#define‎...

profile نویسنده: Alireza Abbasi متخصص الکترونیک

ویراستار: حسین زنجانی زاده
مقالات بیشتر

slide

پالت | بازار خرید و فروش قطعات الکترونیک

قطعات اضافه و بدون استفاده همیشه یکی از سرباره‌‌های شرکتها و طراحان حوزه برق و الکترونیک بوده و هست. پالت سامانه‌ای است که بصورت تخصصی اجازه خرید و فروش قطعات مازاد الکترونیک را فراهم می‌کند. فروش در پالت
family

آیسی | موتور جستجوی قطعات الکترونیک

سامانه آی سی سیسوگ (Isee) قابلیتی جدید و کاربردی از سیسوگ است. در این سامانه سعی شده است که جستجو، انتخاب و خرید مناسب تر قطعات برای کاربران تسهیل شود. جستجو در آیسی
family

سیسوگ‌شاپ | فروشگاه محصولات Quectel

فروشگاه سیسوگ مجموعه ای متمرکز بر تکنولوژی های مبتنی بر IOT و ماژول های M2M نظیر GSM، GPS، LTE، NB-IOT، WiFi، BT و ... جایی که با تعامل فنی و سازنده، بهترین راهکارها انتخاب می شوند. برو به فروشگاه سیسوگ
family

سیسوگ فروم | محلی برای پاسخ پرسش‌های شما

دغدغه همیشگی فعالان تخصصی هر حوزه وجود بستری برای گفتگو و پرسش و پاسخ است. سیسوگ فروم یک انجمن آنلاین است که بصورت تخصصی امکان بحث، گفتگو و پرسش و پاسخ در حوزه الکترونیک را فراهم می‌کند. پرسش در سیسوگ فرم
family

سیکار | اولین مرجع متن باز ECU در ایران

بررسی و ارائه اطلاعات مربوط به ECU (واحد کنترل الکترونیکی) و نرم‌افزارهای متن باز مرتبط با آن برو به سیکار
become a writer
نویسنده شو !

سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.

ارسال مقاله
become a writer
نویسنده شو !

سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.

ارسال مقاله

خانواده سیسوگ

سیسوگ‌شاپ

فروشگاه محصولات Quectel

پالت
سیسوگ فروم

محلی برای پاسخ پرسش‌های شما

سیسوگ جابز
سیسوگ
سیسوگ فروم
سی‌کار

اولین مرجع متن باز ECU در ایران

سیسوگ مگ
آی‌سی

موتور جستجوی قطعات الکترونیکی

سیسوگ آکادمی
پالت

بازار خرید و فروش قطعات الکترونیک

دیدگاه ها

become a writer
نویسنده شو !

سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.

ارسال مقاله
become a writer
نویسنده شو !

سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.

ارسال مقاله