در حین بررسی پروژهای، متوجه چیزی غیرمتعارف شدم که تا به حال ندیده بودم. در برنامه به متغیری اشاره شده بود که هیچ کجا اثری از تعریف آن نبود:
extern uint32_t __ICFEDIT_SB_region_ROM_end__; #define SB_REGION_ROM_END ((uint32_t)& __ICFEDIT_SB_region_ROM_end__)
این در حالی بود که کلمه extern اعلام میکرد در جایی از پروژه، این متغیر تعریف شده.
کل فایلهای پروژه را جستجو کردم. نهایتاً متوجه که این اسم در لینکر هم تکرار شده. با کمی گوگل کردن به مطلبی رسیدم که قرار است در ادامه بهش بپردازیم. یعنی نحوه استفاده و تعریف symbol در فایل linker برای کامپایلر GCC.
اول از همه تاکید کنم نکاتی که در ادامه میگم برای کامپایلر GCC است. اگرچه مشابه این مفهوم را برای سایر کامپایلرها هم داریم اما نحوه تعریفش دیگر این چنین نیست.
قواعد فایل لینکر مثل فایل .C نیست. به همین علت در پروژهای که اشاره کردم، هیچ کجای فایل لینکر عبارت
uint32_t __ICFEDIT_SB_region_ROM_end__;
پیدا نمیشد. و تنها چیزی که در فایل لینکر آمده بود این خط بود:
__ICFEDIT_SB_region_ROM_end__ = 0x08013FFF;
و در واقع این خط داشت __ICFEDIT_SB_region_ROM_end__ را تعریف میکرد.
علاوه بر این نحوه تعریف، تفاوت دیگری هم وجود دارد. در ازای تعریف __ICFEDIT_SB_region_ROM_end__ همچون متغیرهای عادی که در فایل .C تعریف میکنیم، در حافظه میکروکنترلر محلی گرفته نشده! تنها کاری که __ICFEDIT_SB_region_ROM_end__ میکند این است که به ما آدرس 0x08013FFF را نشان میدهد. مفهومی مشابه با نام یک آرایه.
همانطور که میدانید اسم آرایه هم تنها یک آدرس است. آدرسی ثابت، که اشاره به محلی از حافظه دارد که خانههای آرایه از آنجا شروع میشوند. شما نمیتوانید در این آدرس مقداری بریزید. و اگر هم آن را بخوانید، تنها یک آدرس حافظه را خواندهاید.
به خاطر همین تفاوتها بهتره که به جای عنوان متغیر -variable- بهشون بگیم symbol.
حالا ببینیم چگونه میتوان به مقدار یا به عبارتی آدرسی که symbol به آن اشاره دارد، در برنامه .C دسترسی پیدا کرد.
دو راه برای این کار وجود دارد:
1- راه اول همان بود که در ابتدای این پست دیدید:
extern uint32_t __ICFEDIT_SB_region_ROM_end__; #define SB_REGION_ROM_END ((uint32_t)& __ICFEDIT_SB_region_ROM_end__)
به آمدن & قبل از استفاده از symbol در خط دوم توجه کنید. به شخصه این راه را نمیپسندم. اما به هر حال باید آن را بلد باشیم تا اگر جایی -مثل همین پروژه که من را به این مطلب رساند- با آن برخورد داشتید، بدانید قصه از چه قرار است.
2- راه دوم که ارجحتر و خواناتر است:
extern uint32_t __ICFEDIT_SB_region_ROM_end__[]; #define SB_REGION_ROM_END ((uint32_t)__ICFEDIT_SB_region_ROM_end__)
لینکهای (+، + و +) برای مطالعه بیشتر در این خصوص.
سلام من میخواستم یک راه ارتباطی با آقای علی رستمی پیدا کنم که متاسفانه در سایت هیچ قسمتی برای تماس با ما قرار داده نشده است. لطفا اگر این پیام من رو دیدید ایمیلی برای بنده بفرستید. باتشکر