در مقالهی «نکات و ترفندهای بهینهسازی برنامه C برای میکروکنترلر AVR-قسمت اول» به معماری میکروکنترلرهای هشت بیتی AVR و کامپایلر GCC و نکات بهینه سازی حجم برنامه C پرداختیم. در مقاله پیش رو با نکات بیشتری مربوط به کاهش حجم کد برنامه برای بهینه سازی برنامه C آشنا میشویم.
نکات و ترفندهای کاهش حجم برنامه برای بهینه سازی برنامه C
5)ثوابت در برنامه
متغیرها و جداول و آرایههایی که که ثابت هستند و مقدار آنها در طول برنامه تغییر نمیکنند معمولا در حافظهی فقط خواندنی Flash یا EEPROM ذخیره میشوند تا حافظهی با ارزش SRAM اشغال نشود. همانطور که میدانیم ثوابت به صورت عمومی استفاده میشوند و در توابع قابل اعلان نیستند.
با نوشتن کلمهی کلیدی «const» در برنامهی C، میتوان برای کامپایلر مشخص کرد که این مقدار در طول برنامه تغییر نخواهد کرد و یک دادهی فقط خواندنی (Read-Only) است. با این کار فرصتهای بهینه سازی برنامه C توسط کامپایلر افزایش مییابد. با این حال با این کلمهی کلیدی، نوع حافظهی ذخیرهکنندهی داده تعیین نمیشود.
در کامپایلر GCC، برای ذخیرهی داده در حافظهی فقط خواندنی برنامه میتوان از ماکروی «PROGMEM» و تابع «pgm_read_byte» استفاده کرد. این ماکرو و تابع در فایل هدر avr/pgmspace.h تعریف شدهاند. در مثال زیر میتوان تاثیر این تابع را در کاهش حجم اشغالی SRAM مشاهده کرد. حجم اشغالشده در هر دو حافظهی برنامه و داده کاهش یافته و منجر به بهینه سازی حجم برنامه C شده است.
باید توجه داشت به خاطر اینکه سرعت خواندن داده از حافظهی برنامه نسبت به حافظهی داده کندتر است، overhead به وجود میآید. بنابراین اگر نیاز است در برنامه چند بار این مقدار ثابت خوانده شود به جای به کار بردن ماکروی PROGMEM بهتر است از متغیرهای موقت (temporary variable) استفاده کنیم.
شاید برای شما مفید باشد: میکروکنترلر مقصر نیست مقصر برنامه نویسی است
گفتنی است در کامپایلر کدویژن، نوشتن کلمهی کلیدی «flash» در ابتدای تعریف ثوابت برای کامپایلر مشخص میکند که مکان ذخیرهی داده در حافظهی برنامه است. اگر از کلمهی کلیدی «flash» استفاده نشود ثابت در حافظهی فلش ذخیره میشود ولی حافظهی SRAM نیز اشغال خواهد شد چرا که مقدار ثابت از حافظهی فلش در SRAM کپی میشود و در هنگام اجرا مقدار از حافظهی SRAM خوانده میشود.
6) انواع دسترسی استاتیک (Static)
برای دادههای عمومی (global) تا جایی که امکان دارد از کلمهی کلیدی «static» استفاده کنید. اگر متغیرهای عمومی با کلمهی کلیدی «static» تعریف شوند، تنها در فایلی که تعریف شدهاند قابل دسترسی هستند. با این روش از استفادهی متغیر عمومی در دیگر فایلها به عنوان متغیر خارجی (external variable) جلوگیری میشود.
از سوی دیگر تا جایی که امکان دارد کلمهی کلیدی «static» را برای متغیرهای محلی (local) داخل توابع استفاده نکنید. مقدار یک متغیر محلی استاتیک پس از اتمام اجرای تابع تا فراخوانی بعدی تابع باید حفظ شود. بنابراین حافظهی SRAM به صورت پیوسته در طول اجرای برنامه اشغال خواهد شد. میتوان گفت متغیر محلی استاتیک مانند یک متغیر عمومی خواهد بود با این تفاوت که فقط برای یک تابع خاص در دسترس است.
توابع استاتیک برای بهینهسازی برنامه برتری دارند چون تنها در همان فایل قابل دسترس هستند و توسط دیگر فایلها قابل فراخوانی نیستند. اگر تابع استاتیک تنها یک بار در فایل فراخوانی شود و تنظیمات بهینهسازی ( O3 , -O2 , -O1 , -Os- ) فعال باشد، تابع استاتیک به صورت یک تابع inline در نظر گرفته میشود و کد اسمبلی برای آن تولید نخواهد شد. اگر تابع استاتیک بیش از یک بار در برنامه فراخوانی شود در کامپایلر به عنوان تابع inline در نظر گرفته نمیشود.
7)دستورات سطح پایین زبان اسمبلی
برنامه با دستورات کد شده با زبان اسمبلی، بهینهترین کد به شمار میآید. یکی از عیبهای کد اسمبلی غیر قابل حمل بودن (non-portable) است بنابراین به برنامهنویسان توصیه نمیشود. با این حال استفاده از ماکروهای اسمبلی، خوانایی و قابل حمل بودن را بهبود میدهد. از ماکروهای اسمبلی به جای توابع استفاده کنید. برای آشنایی با ماکروهای اسمبلی به بخش راهنمای « Inline Assembler Cookbook » رجوع کنید.
نکات مربوط به بهینه سازی حجم برنامه C به طور کامل بیان شد. در قسمت بعدی مقاله به بهینهسازی سرعت اجرای برنامه و کاهش زمان اجرا میپردازیم.
منبع: Atmel