خوش آموز درخت تو گر بار دانش بگیرد، به زیر آوری چرخ نیلوفری را


آموزش زبان ++C : نوع داده Integer

آموزش زبان ++C : نوع داده Integer
نویسنده : امیر انصاری
یک متغیر از نوع داده Integer متغیری است که برای نگهداری اعداد صحیح که دارای اعشار نمی باشند، استفاده می گردد. برای مثال مقادیر 2-، 1-، 0 ، 1، 2 و ... را می توان در نوع داده Integer ذخیره کرد. زبان برنامه نویسی ++C دارای 5 نوع داده Integer مختلف می باشد که می توانید از آنها استفاده کنید :

نرم افزار سامانه مودیان راهکار



آموزش زبان ++C : نوع داده Integer
نوع داده Char یک مورد خاص می باشد که در آن هم می توانید مقادیر کاراکترها و همینطور integer را نگهداری نمود. در مورد ویژگی های خاص نوع داده char بعدها صحبت خواهیم کرد. در این درس، شما می توانید با آن به عنوان یک integer معمولی برخورد کنید.

تفاوت کلیدی بین انواع مختلف نوع داده Integer در اندازه (size) آنها می باشد که شما را قادر می سازد تا مقادیر بزرگتری را در متغیرها ذخیره کنید. توجه داشته باشید که زبان برنامه نویسی ++C تنها تضمین می کند که integer ها می توانند چندین حداقل اندازه داشته باشند، نه اینکه آنها یک اندازه خاصی داشته باشند. برای درک بهتر این موضوع می توانید موارد مطرح شده در درس قبلی دربارۀ اندازه متغیرها و همینطور عملگر sizeof را مرور کنید.

معرفی integer ها


در مثال زیر چندین نوع integer معرفی شده اند :

char c;
short int si; // valid
short s; // preferred
int i;
long int li; // valid
long l; // preferred
long long int lli; // valid
long long ll; // preferred

با وجودیکه معرفی به صورت short int و long int و همینطور long long int یک معرفی صحیح می باشد، ترجیح ما و شما باید بر آن باشد که از شکل خلاصه شدۀ این موارد یعنی short و long و long long استفاده کنیم. علاوه بر اینکه در این روش تایپ کمتری صورت می پذیرد، افزودن پیشوند int منجر می شود تا شناسایی نوع داده int مشکل تر گردد. ضمن اینکه اگر سهواً فراموش کنید واژه short یا long را به کار ببرید منجر به اشتباه می گردد.

شناسایی integer ها


از آنجایی که اندازه (size) نوع داده char، short، int و long بسته به کامپایلر و همینطور بسته به معماری کامپیوتر متفاوت می باشد، برای آموزش بهتر است که به جای اشاره به این انواع توسط نام آنها به سایز آنها اشاره کنیم. برای همین هنگام اشاره به integer ها به اندازه آنها اشاره می کنیم و نه نام آنها، مثلاً یک integer در اندازه 32 بیتی را به جای long بکار می بریم.

محدوده integer ها و علامت (sign) آنها


همانطور که در درس قبلی یاد گرفتید، یک متغیر با n بیت می تواند 2 به توان n وضعیت مختلف را در خودش ذخیره کند. اما کدام مقادیر خاص را می تواند ذخیره کند؟ ما مجموعه ای از مقادیر خاص را داریم که هر نوع داده می تواند محدوده ای از آنها را ذخیره کند. محدوده یک متغیر از نوع integer با دو عامل تعیین می شود : اندازه آن متغیر در واحد بیت و همینطور علامت دار بودن (signed) یا بدون علامت بودن (unsigned) متغیر.

یک integer از نوع علامت دار (signed integer) می تواند هم اعداد منفی و هم اعداد مثبت را در خودش نگهدارد. اگر بخواهید به صراحت یک متغیر از نوع علامت دار را معرفی کنید می توانید از کلمه کلیدی signed استفاده کنید :

signed char c;
signed short s;
signed int i;
signed long l;
signed long long ll;

طبق قرارداد، کلمه کلیدی signed قبل از نوع داده متغیر قرار می گیرد.

یک متغیر integer از نوع علامت دار (signed integer) که اندازه اش 1 بایت باشد، می تواند اعداد 128- تا 127 را در خودش نگهدارد. هر عددی که در محدوده بین 128- و 127 باشد می تواند با خیال راحت در این نوع متغیر ذخیره گردد.

گاهی اوقات، ما پیشاپیش می دانیم که در یک متغیر خاص نیازی به اعداد منفی نداریم. این وضعیت در مواردی که می خواهیم مقدار یا اندازه چیزی را نگهداری کنیم شایع می باشد، به عنوان مثال ما در مورد اندازه قد افراد نیاز به اعداد منفی نداریم. یک متغیر integer از نوع بدون علامت (unsigned integer) تنها می تواند اعداد مثبت را در خودش ذخیره کند. برای اینکه به صراحت یک متغیر integer بدون علامت را معرفی کنیم از کلمه کلیدی unsigned استفاده می کنیم :

unsigned char c;
unsigned short s;
unsigned int i;
unsigned long l;
unsigned long long ll;

یک متغیر integer بدون علامت (unsigned integer) که اندازه آن 1 بایت باشد، می تواند مقادیر بین 0 تا 255 را در خودش نگهداری کند.

توجه داشته باشید که معرفی یک متغیر به صورت بدون علامت، به این معنا می باشد که دیگر آن متغیر قادر به ذخیره سازی اعداد منفی نخواهد بود، اما در عوض می تواند اعداد مثبت را در محدوده بیشتری نگهداری کند.

حالا که تفاوت بین علامت دار و بدون علامت را متوجه شدید، بیایید به محدوده مقادیری که انواع مختلف متغیرها می توانند ذخیره کنند، نگاهی بیندازیم :

آموزش زبان ++C : نوع داده Integer
برای کسانی که به ریاضی و فرمول علاقمند هستند باید بگوییم، یک متغیر علامت دار با n بیت می تواند محدوده آن را با فرمول زیر تعیین کرد.

آموزش زبان ++C : نوع داده Integer
همچنین در مورد یک متغیر بدون علامت که n بیت داشته باشد فرمول زیر می تواند محدوده را تعیین کند.

آموزش زبان ++C : نوع داده Integer
آنهایی هم که زیاد دوست ندارند وارد فرمول ها و قضایای ریاضی شوند ... کافیست تا به جدول بالا مراجعه کنند.

برنامه نویسان جدید معمولاً متغیرهای علامت دار و بدون علامت را با هم قاطی می کنند. در ادامه روش ساده ای برای بیاد آوری تفاوت بین این دو ارائه می کنیم : برای اینکه بین اعداد منفی و اعداد مثبت تمایز قائل شویم، معمولاً از یک علامت منفی (-) استفاده می کنیم. اگر این علامت قرار نداشته باشد، مفروض ما بر اینست که عدد مربوطه مثبت می باشد. در نتیجه، یک متغیر integer دارای علامت، می تواند تفاوت بین اعداد منفی و مثبت را بگوید. در یک متغیر integer بدون علامت، تمامی اعداد مثبت مفروض می شوند.

علامت های پیش فرض (Default signs) و بهترین شیوه های استفاده از integer


اگر ما کلمات کلیدی signed (به معنای علامت دار) یا unsigned (به معنای بدون علامت) را استفاده نکنیم، چه اتفاقی می افتد؟

آموزش زبان ++C : نوع داده Integer
همانطور که جدول بالا نشان می دهد، تمامی متغیرهای از نوع integer (به جز char) به صورت پیش فرض دارای علامت (signed) مفروض می شوند. نوع داده char می تواند در اینگونه مواقع علامت دار و یا بدون علامت مفروض شود که البته معمولاً آنهم پیش فرضش علامت دار می باشد.

به صورت کلی، معمولاً کلمه کلیدی signed به جز در هنگام معرفی متغیرهای از نوع char استفاده نمی شود. مگر اینکه بخواهید از علامت دار بودن مطمئن باشید و به صراحت کلمه کلیدی signed را بکار ببرید.

بهترین روش برای جلوگیری از خطاها اینست که از نوع بدون علامت (unsigned) به جز در موارد خیلی خاص که واقعاً به آنها نیاز دارید، استفاده نکنید. چرا که استفاده از کلمه کلیدی unsigned می تواند برنامه شما را بیشتر مستعد خطا کند.

قانون : ترجیح شما همیشه بر این باشد که از متغیرهای integer علامت دار (signed integer) استفاده کنید.

خطای سرریز (Overflow)


اگر بخواهیم عددی را خارج از محدوده ای که یک متغیر از نوع integer می تواند نگهداری کند، در آن ذخیره کنیم، چه اتفاقی می افتد؟ در این صورت خطای سرریز (Overflow) اتفاق می افتد، در این حالت ما بیت هایی از اطلاعات را از دست می دهیم چرا که به آن متغیر به میزان کافی حافظه تخصیص داده نشده است.

در آموزش مربوط به معرفی متغیرها، مقدار دهی اولیه و انتساب، اشاره کردیم که داده ها در قالب باینری ذخیره می گردند. در قالب باینری (مبنای 2)، هر رقم تنها می تواند دو مقدار ممکن 0 یا 1 را ذخیره کند. به عنوان مثال مقادیر 0 تا 15 را می توانیم مشابه جدول زیر در قالب باینری داشته باشیم :

آموزش زبان ++C : نوع داده Integer
همانطور که خودتان هم در جدول می توانید ببینید، اعداد بزرگتر نیاز به تعداد بیت های بیشتری دارند. از آنجا که متغیرهای ما تعداد ثابتی از بیت ها را دارند، محدودیتی در زمینه مقدار داده های ذخیره شده وجود دارد.

مثال هایی از خطای سرریز (Overflow)


یک متغیر نامعلوم فرضی را از نوع بدون علامت (unsigned) در نظر بگیرید که می تواند تنها 4 بیت را در خودش ذخیره کند. در این صورت هر کدام از اعداد موجود در جدول بالا می تواند در آن متغیر جا بگیرد (چرا که هیچ کدام از آنها نیاز به فضای بیشتر از 4 بیت ندارند).

اما اگر بخواهیم مقداری را که بیش از 4 بیت فضا نیاز دارد در آن متغیر ذخیره کنیم چه اتفاقی می افتد؟ ما دچار خطای سرریز (Overflow) می شویم : در اینصورت تنها بخشی از مقدار مورد نظر ما می تواند در آن متغیر ذخیره گردد و بقیه داده ها از دست می روند.

برای مثال، اگر بخواهیم عدد 21 را در یک متغیر 4 بیتی ذخیره کنیم :

آموزش زبان ++C : نوع داده Integer
عدد 21 که معادل باینری آن 10101 می باشد، 5 بیت نیاز دارد. 4 بیت سمت راست آن 0101 در داخل متغیر ذخیره می شود، و یک بیت سمت چپ آن (1) به سادگی گم می شود. در حال حاضر متغیر ما مقدار 0101 را در خودش دارد که معادل عدد 5 می باشد.

توجه : در این مرحله از آموزش، از شما انتظار نمی رود که بدانید چگونه مقادیر عددی در مبنای 10 (decimal) به مقادیر باینری (binary) تبدیل می شوند و یا برعکس آن. در این مورد در آموزش های آینده بیشتر بحث خواهیم کرد و به جزئیات این فرآیند که نامش Converting between binary and decimal می باشد، خواهیم پرداخت.

حالا، بیایید به یک مثال نگاه کنیم که طی آن در یک کد واقعی به این موضوع پرداخته ایم. فرض ما بر اینست که نوع داده short ما در این مثال 16 بیتی می باشد :

#include "iostream"

int main()
{
unsigned short x = 65535; // largest 16-bit unsigned value possible
std::cout << "x was: " << x << std::endl;
x = x + 1; // 65536 is out of our range -- we get overflow because x can't hold 17 bits
std::cout << "x is now: " << x << std::endl;
return 0;
}

خروجی این برنامه به شکل زیر خواهد بود :

x was: 65535
x is now: 0

چی شد؟ ما سعی کردیم تا مقداری (مقدار 65536) بزرگتر از محدوده متغیر short را در آن ذخیره کنیم. برای همین مقدار متغیر به مقدار پیش فرض اصلی اش باز گشت.

برای خوانندگان حرفه ای تر این مطلب باید بگوییم در اینجا این اتفاق در پشت صحنه افتاده است : عدد 65,535 در مبنای باینری برابر با 1111111111111111 می باشد. همچنین عدد 65,535 بزرگترین مقداری می باشد که یک متغیر 2 بایتی (16 بیتی) بدون علامت می تواند در خودش ذخیره کند، و تمامی آن 16 بیت را اشغال می کند. هنگامی که در کد عدد 1 را به آن اضافه می کنیم، مقدار جدید ما برابر با 65,536 می گردد. عدد 65,536 در مبنای باینری برابر با 10000000000000000 می باشد که 17 بیت را دارد. در نتیجه یک بیت از این اطلاعات از سمت چپ از دست می رود که همان بیت دارای مقدار 1 می باشد و 16 بیت سمت راست باقی می مانند. حالا عدد باینری ذخیره شده در متغیر در واقع 0000000000000000 می باشد، که معادل دهدهی (decimal) آن عدد 0 می باشد.

به طور مشابه، می توانیم مقدار حداقلی این متغیر را نیز تعمداً دچار مشکل خطای سرریز (Overflow) کنیم، در اینصورت مقدار متغیر به بالاترین محدوده باز می گردد.

#include "iostream"

int main()
{
unsigned short x = 0; // smallest 2-byte unsigned value possible
std::cout << "x was: " << x << std::endl;
x = x - 1; // overflow!
std::cout << "x is now: " << x << std::endl;
return 0;
}

x was: 0
x is now: 65535

خطای سرریز (Overflow) منجر به از دست دادن داده ها می شود، که معمولاً هرگز مطلوب نمی باشد. اگر هر گونه سوء ظن دارید که متغیر شما نیاز به ذخیره مقادیر بزرگتری را دارد و ممکن است که از محدوده پیش بینی شده فراتر رود، یک نوع داده بزرگتر را در معرفی متغیر استفاده کنید!

همچنین توجه داشته باشید که نتایج خطای سرریز (Overflow) تنها در مورد متغیرهای integer بدون علامت (unsigned integer) قابل پیش بینی می باشند. نتایج خطای سرریز (Overflow) در مورد متغیرهای integer دارای علامت (signed integer) ممکن است منجر به موارد غیر قابل پیش بینی در سیستم های مختلف گردد.

قانون : هرگز مبتنی بر نتایج خطای سرریز (Overflow) کدی را در برنامه خود ننویسید، چرا که ممکن است در سیستم های مختلف نتایج متفاوتی را در بر داشته باشد.

تقسیم در integer ها


هنگامی که از دو متغیر نوع integer در عملیات تقسیم استفاده می کند، در نتیجه تقسیم در زبان ++C اعداد صحیح نمایش داده می شوند :

#include "iostream"

int main()
{
std::cout << 20 / 4;
return 0;
}

خروجی این کد عدد 5 می باشد :

5

اما بیایید ببینیم اگر باقیمانده تقسیم ما عددی اعشاری باشد چه اتفاقی می افتد :

#include "iostream"

int main()
{
std::cout << 8 / 5;
return 0;
}

نتیجه غیر منتظره می باشد :

1

هنگامی که در زبان برنامه نویسی ++C دو عدد integer را بر یکدیگر تقسیم کنید، نتیجه عملیات نیز یک مقدار integer می باشد و از آنجا که مقادیر integer قادر به ذخیره سازی بخش کسری اعداد نمی باشند، آن قسمتها از نتیجه حذف می گردند. دقت کنید که حذف می گردند و رند نمی شوند.

اگر با دقت بیشتری به مثال 5 / 8 نگاه کنید، متوجه خواهید شد که نتیجه آن 1.6 می باشد و اگر بنا بود رند شود باید تبدیل به 2 می شد. اما بخش اعشاری آن یعنی 0.6 به طور کل از نتیجه حذف شده و در نهایت عدد 1 به عنوان پاسخ تقسیم نمایش داده می شود.

قانون : هنگامی که در متغیرهای از نوع integer عملیات تقسیم را انجام می دهیم، دقت کنید که باقی مانده تقسیم شما بخش اعشاری نداشته باشد، و اگر داشته باشد با نتایج غیر منتظره مواجه خواهید شد.


آموزش قبلی : آموزش زبان ++C : اندازه متغیرها و عملگر sizeof

آموزش بعدی : آموزش زبان ++C : متغیرهای integer با عرض ثابت و مبحث متغیرهای بدون علامت



نمایش دیدگاه ها (0 دیدگاه)

دیدگاه خود را ثبت کنید:

انتخاب تصویر ویرایش حذف
توجه! حداکثر حجم مجاز برای تصویر 500 کیلوبایت می باشد.