خب تو این قسمت میخواهیم بررسی کنیم چطور میتونیم تو برنامه ای که مینویسیم مشخص کنیم که یه قسمت مدنظر ما تو کدوم یک از بخش های حافظه ذخیره بشه. کلمات کلیدی زبون C که میتونن برای رسیدن به این هدف بهمون کمک کنن اینا هستند:
- Variable Types
- Type Qualifiers
- Type Modifiers
- Storage Classes
اولین مورد از موارد فوق مشخص میکنه که نوع متغیری که میخوایم تعریف کنیم چیه. این قضیه به طور مستقیم روی حافظه ای که قراره این متغیر اشغال کنه تاثیر میذاره. انواع متغیر مثه char ,float ,int و … هرکدوم مقدار مشخصی از حافظه رو اشغال میکنند.
دومین مورد که ما معمولا با کلمه کلیدی const ازش استفاده میکنیم باعث میشه متغیر تعریف شده صرفا قابل خواندن باشه و نشه مقدارش رو تغییر داد. البته کلمه های کلیدی دیگه ای هم تو این دسته جا میگیرند. این متغیرها معمولا در Code segment حافظه و در زیربخش const. قرار میگیرن.
مورد سوم از موارد فوق اندازه و علامت دار یا بی علامت بودن متغیر رو مشخص میکنه. کلماتی از قبیل signed ,short ,long و … از این دست هستند.
آخرین مورد هم مدت زمان باقی موندن متغیر در حافظه و همین طور محدوده دسترسی به متغیر رو مشخص میکنه. چهار مورد مهم تو این دسته قرار میگیرن:
- Auto
این کلمه مشخص میکنه که این متغیر باید در قسمت stack حافظه ذخیره بشه و مقدار دهی براش صورت بگیره. متغیرهایی که Storage class براشون تعریف نمیشه به صورت پیش فرض از همین دسته در نظر گرفته میشن.
- Static
این کلمه میگه که متغیر تعریف شده باید در کل فرایند اجرای پروژه ثابت بمونه و نباید فضایی رو که توی حافظه اشغال کرده ازش گرفته شه به همین خاطر هم طبق توضیحات قبلی بسته به نوع مقدار دهی تو بخش bss یا data از Data segment حافظه ذخیره میشه. فرق مهمی که این نوع داده با داده های سراسری داره اینه که اگه این داده مثلا داخل یه تابع تعریف شه فقط از داخل همون تابع قابل دسترسی هستش و خارج اون نمیشه بهش دسترسی داشت (اگرچه حافظه ای رو که اشغال کرده پس نمیده!)
- Extern
از این کلمه هم در مواقعی استفاده میشه که یک متغیر سراسری رو بخوایم در فایلی غیر از فایلی که متغیر رو توش تعریف کردیم استفاده کنیم. یه جورایی میشه گفت مفهوم سراسری بودن یه متغیر رو گسترش میده.
- Register
این کلمه رو زمانی به کار میبریم که بخوایم داده ای رو به صورت مستقیم در رجیسترهای CPU ذخیره کنیم. بدیهی هستش که چون رجیسترها پرسرعت ترین منابع حافظه در میکروکنترلر ها هستند پس این کار قاعدتا سرعت اجرا رو افزایش خواهد داد ولی این موضوع مشکلاتی رو هم ایجاد میکنه. فرض کنید برای انجام یه عملیات تمام رجیسترهای CPU غیر یکی مشغول باشند و اون یه دونه رو هم شما به این طریق استفاده میکنید. چی میشه؟ اون عملیات به علت اینکه رجیستری برای استفاده نداره انجام نمیشه و اینطوری ممکنه برنامه Performance رو از دست بده. به همین خاطر هم معمولا تو برنامه نویسی ما این کار رو انجام نمیدیم و ترجیح میدیم اینطور بهینه سازی ها رو کامپایلر برامون انجام بده!
در تصویر زیر میتونید مثالی رو مشاهده کنید که از تمام مواردی که تا الان توضیح دادیم نمونه هایی رو داره. نامگذاری متغیرها به نحوی انجام شده که مشخص میکنه هر کردومشون تو کدوم قسمت از حافظه ذخیره میشن:
سلام
پس volatile چی میشه؟
اونم مگه کلاس ذخیره سازی نیس؟!
بله لطفا در مورد volatile هم توضیح بدید
سلام و ممنون از توضیحاتتون
در قسمت تعریف نوع چه فرقی بین ذخیره سازی متغیر های هم سایز وجود داره (مثلا بین uint_8 و char ) و اینکه مثلا در تابعی که خروجی 8 بیتی دارد از کدام نوع استفاده میکنیم و آیا به جای هم می توان به کار برد یا خیر؟ ممنون