دیدم بحث خوبی شروع شده گفتم از طریق یه سری مثال در قالب پرسش و پاسخ یه کم بحث را تکمیل کنم
البته بیشتر تمرکز روی متغیرها هست. در مورد تابع ها و تمپلیت ها وکلاس و غیره هم مطلب هست که فعلا ازش صرفنظر می کنیم
سوال: از مطالب بالا یه چیزایی فهمیدم اما معلوم نشد متغیر با مدت حافظه static به چه دردی می خوره؟
جواب: همون طور که گفتم این متغیر با شروع برنامه شروع و تا پایان برنامه ادامه خواهد داشت همچنین مقدار دهی اولیه این متغیرها یک بار در طول برنامه انجام میشه مثلا مثال زیر را ببیند
#include <iostream>
using namespace std;
void f1()
{
static int a=0;
a++;
cout<<a<<endl;
}
int main()
{
f1();
f1();
f1();
return 0;
}
متغیر محلی a که لینکیج نداره و مدت حافظه اون هم static هست تنها یکبار مقدار دهی اولیه میشه و دفعات بعدی که تابع f1 صدا زده میشه مقدار دهی اولیه نمیشه و فقط به مقدار اون اضافه میشه
سوال: منظورت چیه که متغیر محلیه؟
جواب: متغیریه که در محدوده بلاک اعلان میشه، محلیه. همچنین متغیر عمومی هم داریم. بهتره بدونیم تمام کدهای موجود در یک واحد ترجمه از قبیل تابع main و .. درون یک فضای نام قرار دارند؛ اگرچه ما اون فضای نام را تعریف نمی کنیم. اون «فضای نام عمومی» هست. مثلا متغیرهایی که بعضی وقتها دیده میشه قبل از تابع main قرار دارن جزء متغیر عمومی به حساب میان و از اعضای فضای نام عمومی هستند مثل a1
int a1=2;
int main()
{
//...
}
سوال: آیا اگه بخواهیم مدت حافظه یک متغیر static باشه حتما لازمه کلمه static را قبل از اعلان اون بیاریم؟
جواب: در مورد متغیرهای محلی لازمه . اما تمام متغیرهایی که محلی نباشن و مدت حافظه اونها dynamic و thread نباشه static هستند. مثل متغیر a1 در مثال بالا که مدت حافظه اون static هست
سوال: گاهی وقتها دیده میشه یک متغیر عمومی به صورت static تعریف میشه در صورتی که می دونیم که static هست. (مثل متغیر a2 در مثال زیر) پس به کار بردن کلمه static چه ضرورتی داره؟
static int a2=2;
int main()
{
//...
}
جواب: به کار بردن کلمه static باعث میشه که لینکیج اون داخلی بشه چون متغیرهای موجود در یک فضای نام دارای لینکیج خارجی هستند ( به تبعیت از فضای نام در برگیرنده اونها) مگر این موارد که داخلی هستند:
-متغیری که با کلمه static اعلان بشه
-متغیری که به صورت const یا constexpr اعلان شده باشه اما این اعلان با کلمه extern همره نباشه و یا قبلا اعلان نشده باشه که اون متغیر دارای لینکیج خارجیه
سوال: این طور که معلوم شد تمام فضای نامها دارای لینکیج خارجی هستن. آیا درست فهمیدم؟
جواب: نه اینطور نیست. یک فضای نام بدون نام و یا فضای نامی که به صورت مستقیم یا غیر مستقیم درون یک فضای نام بی نام اعلان شده باشه لینکیج داخلی داره
سوال: پس یک روش برای اینکه حتما یک متغیر دارای لینکیج داخلی بشه اینه که اون را داخل یک فضای نام بی نام بذاریم. مثل مورد زیر
namespace {
static int a3=2;
int a4;
}
جواب: آفرین به نکته خیلی خوبی اشاره کردی.
سوال: یک نکته جالب که از مطالب بالا فهمیدم برای اینکه لینکیج یک متغیر خارجی بشه حتما لازم نیست از کلمه extern استفاده بشه
جواب: همین طوره. حتی در بعضی موارد اعلان یک متغیر با کلمه extern لزوما باعث نمیشه لینکیج اون خارجی بشه
سوال: دیگه دارم شاخ در میارم. این دیگه چه صیغه ای یه؟
جواب: اگه ما داخل محدوده یک بلاک متغیری را با کلمه extern اعلان کنیم و این در صورتی باشه که قبل از اون یک متغیر با همان نام و نوع را اعلان کرده باشیم که دارای لینکیج هم باشه ( بدون لینکیج نباشه)، و متغیر اولی توسط دومی قابل رویت باشه، متغیر دومی ، لینکیج متغیر اولی را دریافت می کنه
دوباره مثل چند پست قبل دو تا فایل به نام s1.cpp و s2.cpp درست کنید
در فایل s1 متغیری به نام a5 در فضای نام عمومی تعریف کردیم که خود به خود دارای لینکیج خارجی هست
در فایل s2 قبل از تابع main متغیر a5 را به صورت static تعریف کردیم که باعث میشه مدت حافظه اون static و لینکیج اون داخلی بشه
در تابع main متغیر a5 را به صورت extern اعلان کردیم اما چون a5 دومی داره یک a5 دیگه را می بینه که اتفاقا دارای لینکیج هم هست ، بنابراین لینکیج اون را دریافت می کنه و قادر به دسترسی به a5 موجود در فایل s1 نیست و عدد 8 چاپ میشه ( همچنین مدت حافظه a5 دومی هم static میشه)
//file s1.cpp
int a5=7;
//file s2.cpp
#include <iostream>
using namespace std;
static int a5=8;
int main()
{
extern int a5;
cout<<a5<<endl;
return 0;
}
سوال: دیگه دارم خسته میشم فقط یه سوال ته دلم مونده که اگه نپرسم فکر می کنم بحث ناقص مونده.
جواب: بفرما این یکی هم بپرس
سوال: حالا a5 دومی موجود در فایل s2 چه طور می تونه به a5 موجود در فایل s1 دسترسی داشته باشه؟
جواب: اگه a5 دومی اصلا متغیری به این نام را نبینه یا اینکه متغیری به این نام را ببینه اما متغیر اولی دارای لینکیج نباشه، متغیر دوم دارای لینکیج خارجی میشه و ومی تونه به a5 موجود در فایل s1 دسترسی پیدا کنه
در مثال زیر در فایل s2 اصلا متغیری با نام a5 ایجاد نمیشه و لینکیج خارجی میشه
//file s2.cpp
#include <iostream>
using namespace std;
int main()
{
extern int a5;
cout<<a5<<endl;
return 0;
}
اما در موردزیر چون a5 اولی داخل بلاک تعریف شده لینکیج نداره و فقط مدت حافظه اون static هست اما و تا قبل از اینکه به extern برسیم اون a5 هست که قابل دسترسی میشه اما وقتی به extern برسیم a5 دارای لینکیج خارجی میشه و a5 اولی از دسترسی خارج و a5 موجود در فایل s1 قابل دسترسی میشه
//file s2.cpp
#include <iostream>
using namespace std;
int main()
{
static int a5=8;
{
cout<<a5<<endl;
extern int a5;
cout<<a5<<endl;
return 0;
}
}
سوال: بحث جالبی بود
جواب: امیدوارم مفید بوده باشه