کلاس های حافظه
کلاس حافظه (storage class) تعيين می کند چگونه حافظه به متغيرها توسط کامپايلر واگذار شود. فضای حافظه برای ذخيره متغيرها و توابع و طول عمر اين فضا در طول اجرای برنامه توسط کلاس حافظه مشخص می شود.
محل ذخيره و محدوده متغيرها بسته به محلی (که می تواند داخل يا خارج بدنه تابع باشد) دارد که تعريف می شوند. وقتی پيش فرض های ذخيره سازی شما را راضی نمی کنند می توانيد از کلاس های حافظه استفاده کنيد.
کلاس های حافظه در C و ++C عبارتند از:
auto •
register •
static •
extern •
typedef •
mutable •(تنها در ++C)
auto
اگر کلمه کليدی auto را قبل از اعلان متغيری قرار دهيد صريحا نوع ذخيره سازی اتوماتيک (automatic storage) را برای متغير مدنظر گرفته ايد. متغيری که ذخيره سازی اتوماتيک دارد با خروج از بلاکی که در آن تعريف شده پاک می شود. حافظه زمان ورود به بلاک اختصاص و زمان خروج از آن آزاد می شود.
مثال. اعلان صريح يک متغير اتوماتيک.
auto int i;
دسترسی به متغير از طريق اسم آن است. بخشی از برنامه است که نام متغير در آن قابل رويت است ميدان يا حوزه (scope) ناميده می شود.
ميدان عمل متغيرهای اتوماتيک درون بلاکی است که در آن اعلان شده اند و خارج از آن قابل رويت نيستند. به همين دليل به آنها متغيرهای محلی نيز گفته می شود.
کلاس auto برای متغيرهای محلی و درون بلاک نوع پيش فرض است و نيازی به ذکر کلمه auto نيست.
نکته. کلاس auto را می توانيد برای متغيرهای درون يک بلاک يا پارامترهای تابع اعمال کنيد.
نکته. با اشاره گرها می شود به متغيرهای محلی از خارج بلاک دسترسی پيدا کرد.
نکته. اگر متغير اتوماتيک مقداردهی اوليه نشود مقدارش نامعلوم خواهد بود. اگر يک مقدار اوليه تعيين کنيد هر زمان که وارد بلاکی که متغير در آن تعريف شده شود مقدار به متغير تخصيص داده می شود.
نکته. اگر از دستور goto برای پرش به بلوکی استفاده کنيد متغيرهای اتوماتيک مقداردهی نمی شوند.
نکته. اگر متغيری درون تابع بازگشتی اعلان شود در هربار فراخوانی تابع حافظه ايجاد و مقداردهی می شود.
register
ثبات ها حافظه هائی درون خود CPU هستند که داده آنها می تواند به سرعت دسترسی شود. معمولا کامپايلر تعيين می کند چه زمانی چه داده ای بايد در ثبات ذخيره شود. با وجود اين کلاس register اين امکان را به برنامه نويس می دهد که به کامپايلر بگوييد در صورت امکان متغير اتوماتيکی را درون ثبات ذخيره کند.
کامپايلر مجبور به اجرای اين درخواست نيست زيرا اندازه و تعداد ثبات های موجود در سيستم محدود است و تعداد کمی از متغيرها می توانند حقيقتا در ثبات ها قرار گيرند. اگر کامپايلر ثباتی را اختصاص ندهد با متغيرثباتی مانند متغير اتوماتيک برخورد می کند.
مثال. اعلان متغير از کلاس ثبات.
register int var;
نکته. متغيرهای ثباتی نوعی متغير اتوماتيک محسوب می شوند.
نکته. متغيرهای ثبات بايد درون يک بلاک يا به صورت پارامتر تابع اعلان شده باشند.
نکته. ذخيره سازی کلاس ثبات از نوع اتوماتيک است يعنی با ورود به بلاک ايجاد و در انتها از بين می رود.
نکته. متغيرهای ثبات را می توان مقداردهی اوليه داد.
نکته. در C اشاره گر به متغير ثبات نمی توانيد داشته باشيد. اما C++ اجازه می دهد آدرس متغير از نوع ثبات را بگيريد.
نکته. کلاس ثبات را نمی توانيد برای اشيای درون فضای اسمی استفاده کنيد.
static
متغيرهایئی که با کلاس static اعلان می شوند طول عمر ذخيره ايستا (static storage duration) دارند. بدين معنی که حافظه ثابتی از زمان شروع اجرای برنامه به آنها اختصاص داده می شود و تا پايان اجرای برنامه آزاد نمی شود.
مثال. اعلان و مقداردهی متغيری از کلاس ايستا.
static int staticInt = 5;
متغيرهای static به حياط خود حتی بعد از خروج از بلاکی که در آن تعريف شده اند ادامه می دهند. بنابراين مقدار متغير در تابع بين فراخوانی های مکرر همان تابع حفظ می شود.
مثال. فرض کنيد متغير x در تابع ()f اعلان شده است که تا زمان اجرای برنامه باقی می ماند.
#include <iostream.h>
int f(void) {
static int x = 0;
x++;
return x;
}
int main(void) {
int j;
for (j = 0; j < 5; j++) {
cout << "Value of f(): " << f() << endl;
}
return 0;
}
چون x از نوع static است هربار صفر نمی شود، بلکه مقدار قبلی خود را در تابع حفظ می کند. خروجی برنامه به صورت زير خواهد بود:
Value of f(): 1
Value of f(): 2
Value of f(): 3
Value of f(): 4
Value of f(): 5
نکته. متغير static درون بلاک تنها يکبار مقداردهی می شود در حاليکه متغير auto هربار که اجرا وارد بلاک شود مقداردهی می شود.
نکته. اگر يک متغير static صريحا مقداردهی نشود مقداراوليه صفر را می گيرد.
نکته. کلاس static مادام العمر هستند اما مشابه auto می توان ميدان آنها را محدود به بلاک کرد.
نکته. کلاس static می تواند برای متغيرهای اتوماتيک و خارجی هم استفاده بشود.
extern
کلمه کليدی extern برای توصيف متغيری است که خارجی تعريف شده است. متغيرهای خارجی بيرون از هر بلاکی درون يک فايل اعلان می شوند و می توانند خارج از فايلی که در آن تعريف شده است استفاده شوند.
با کلاس extern متغيرها و توابعی را می توان تعريف کرد که در چندين فايل قابل دسترسی هستند.
مثال. اگر برنامه شامل چندين فايل منبع file1.cpp، file2.cpp و file3.cpp باشد. متغيری که در فايل file1.cpp تعريف است در دو فايل ديگر همراه با کلمه extern بايد ذکر شود تا قابل دسترسی باشد.
حافظه چنين متغيرهائی زمان شروع اجرای برنامه اختصاص داده می شود و تا انتهای برنامه باقی می ماند. ميدان متغيرهای خارجی سراسری است يعنی در کل متن فايل بعد از خطی که اعلان شده اند قابل دسترسی هستند.
متغيرهای خارجی ممکن مانند متغيرهای اتوماتيک با يک مقدار ثابت مقداردهی شوند. مقداردهی در زمان کامپايل تنها يکبار وقتی حافظه اختصاص داده می شود انجام می شود.
چون هر تابعی در برنامه می تواند به متغير خارجی دسترسی پيدا کند اشکال زدائی برنامه سخت تر خواهد شد. به همين علت شايد بهتر باشد از متغيرهای خارجی استفاده نشود. اما گاهی متغيرهای خارجی باعث ساده تر شدن پياده سازی الگوريتم می شود.
نکته. در اکثر کامپايلرها مقداراوليه صفر به متغيرهای خارجی داده می شود.
نکته. اگر تابعی متغيرمحلی هم نام با خارجی داشته باشد درون تابع ارجاع به متغير محلی خواهد بود.
نکته. در عمل بهتر است کليه اعلانات extern در يک فايل هدر جمع شده و فايل با راهنمای include# ضميمه شود.
نکته. در ++C اعلان خارجی نمی تواند در داخل کلاس ظاهر شود.
typedef
اعلان typedef به شما اجازه می دهد شناسه های خودتان را تعريف کنيد که می توانند جای نوع داده نظير int يا float را بگيرند. يک اعلان typedef محلی برای ذخيره نمی گيرد و نوع داده جديدی نيست بلکه مترادفی برای انواع داده يا ترکيبی از آنهاست.
Typedef بخاطر شباهت های گرامری در دسته شاخص های کلاس حافظه گروه بندی می شود.
مثال. عبارت زير LENGTH را مترادف با int اعلان می کند.
typedef int LENGTH;
LENGTH length, width, height;
اعلان زير معادل مثال قبل است:
int length, width, height;
مثال. اعلان يک ساختمان توسط typedef. متغيرهای chicken، cow، horse و whale از نوع ساختمان WEIGHT تعريف شده اند.
typedef struct {
int scruples;
int drams;
int grains;
} WEIGHT;
WEIGHT chicken, cow, horse, whale;
مثال. يک کلاس توسط typedef بدون نام تعريف شده و يک نام مستعار Trees را گرفته. چنين کلاس هائی نمی توانند سازنده و مخرب داشته باشند. ()Trees نمی تواند سازنده برای کلاس باشد.
typedef class {
Trees();
} Trees;
mutable
کلاس ذخيره mutable تنها روی اعضای داده ای يک کلاس می تواند اعمال شود و باعث می شود اين اعضا حتی اگر در کلاس به صورت const تعريف شده اند قابل تغيير باشند.
مثال. در اين برنامه کامپايلر اجازه نمی دهد انتساب var2.y=2345 انجام بشود زيرا var2 به صورت يک ثابت تعريف شده است. اما var2.x=345 اجرا می شود چون A::x به صورت mutable اعلان شده است.
class A {
public:
A() : x(4), y(5) { };
mutable int x;
int y;
};
int main() {
const A var2;
var2.x = 345;
// var2.y = 2345;
}
نکته. کلاس mutable را نمی توانيد همراه با static يا const اعلان کنيد.