سلام.

در مورد شیفت بیتی متاسفانه خیلی ها مشکل دارن بچه های کامپیوتر که اصلا باهاش کاری ندارن برای همین شاید ندونن دقیقا چطور کار میکنه و بچه های برق هم فکر میکنن چون مربوط به برنامه نویسی هست حق دارن که نمیدونن شیفت بیتی دقیقا چیه و چطور کار میکنه

برای همین اومدم کمی راجع بهش توضیح بدم 

ابتدا بگم من این مطلب رو 4 سال پیش نوشتم و الان اومدم بعد از 4 سال ویرایشش کنم (تاریخ امروز: ۹۸/۱۲/۵ و تاریخ انتشار اول این مطلب: ۹۴/۹/۱۹) چون فکر میکنم میتونم الان بهتر توضیح بدم و الان خودم بیشتر ازش سردر میارم.

احتمالا شما که اومدید این مطلب رو میخونید رشته تون الکترونیک هست یا علاقه مند به الکترونیک هستید چون بعید هست که یه کامپیوتری به این چیزا احتیاج پیدا کنه

من در ابتدا اصل موضوع شیفت رو توی زبان برنامه نویسی سی توضیح میدم بعد میریم سراغ کاربردش توی الکترونیک و احتمالا برنامه نویسی میکرو ها.

 

خوب شیفت بیتی همونطور که از اسمش پیداست یک عملگر بیتی هست یعنی روی بیت ها عمل میکنه در نتیجه شما در هنگام کار با این عملگر باید به صورت بیتی فکر کنید.

دو نوع شیفت داریم. شیفت راست و شیفت چپ. با مفهوم شیفت احتمالا در عامیانه آشنایی دارین. وقتی یه چیزی رو شیفت راست میدیم همه عناصر اون یک واحد به سمت راست میان

توی اعداد باینری هم به همین صورت هست

فرض کنید عدد باینری زیر رو داریم 

110100100

حالا میخوایم یک واحد به راست شیفت بدیم. به نظرتون جواب چی میشه؟

همه یکی میان سمت راست و جواب میشه

11010010

خوب اگه اون عدد اول رو بخوایم این دفعه شیفت به چپ بدیم چی شکلی میشه؟

همه یکی میان سمت چپ و عدد حاصل میشه:

1101001000

خوب برای اینکه همه یکی بیان سمت چپ باید یک صفر تهش اضافه کنیم.

 

یه نکته: اگه عدد ما 101011 بود و خواستیم شیفت راست بدیم اون عدد یک اول از دست میره و عدد ما میشه 10101 پس اصلا برامون مهم نیست که تهش صفر باشه یا یک هرچی باشه پاک میشه و همه یکی میان سمت راست (البته یه چیزایی تحت عنوان شیفت چرخشی و شیفت ریاضی هم داریم که روی همین موضوع با هم اختلاف دارن که ما باهاشون کاری نداریم ولی اگه خواستید میتونید سرچ کنید و بخونید شاید توضیحش یک خط باشه)

 

از نظر ریاضی چه اتفاقی میوفته؟

فکر کنید عدد 100 داریم که به دهدهی میشه 4 اگه شیفت به راست بدیم عدد حاصل میشه 10 که توی دهدهی میشه 2 و این یعنی شیفت به راست عدد ما رو بر دو تقسیم میکنه

برای شیفت به چپ هم عدد ما در 2 ضرب میشه. مثلا عدد 11 که برابر 3 در سیستم اعداد دهدهی هست رو اگه یک بیت به چپ شیفت بدیم میشه 110 که میشه 6 یعنی شد دوبرابر.

نکته: ما وقتی توی سیستم اعداد دهدهی یک صفر جلوی عدد میزاریم انگار در 10 ضرب کردیم (مثلا 45 و 450) و هنگامی که یک صفر حذف میکنیم انگار بر 10 تقسیم کردیم (مثلا 50 و 5) این اتفاق دقیقا توی سیستم اعداد دودویی هم میوفته پس چیز جدید یا عجیبی نیست....

حالا بریم ببینیم شیفت راست و چپ توی زبان برنامه نویسی سی چگونه کار میکنه

توی زبان سی شیفت به چپ رو با >> نشون میدن و شیفت به راست رو با << نشون میدن

مثلا فرض کنید میخوایم بگیم عدد 11010 رو به چپ شیفت بده باید بنویسیم:

11010 << 1

این یعنی عدد 11010 رو یک بیت به چپ شیفت بده که میشه 110100 

حالا فرض کنید بخوایم این عدد رو به راست شیفت بدیم در این صورت داریم:

11010 >> 1

که جوابش میشه 1101

 

خب حالا فرض کنید بخوایم این عدد رو دو بیت به راست شیفت بدیم داریم:

 

11010 >> 2

که جوابش میشه 110، پس دید که کار خاصی نداره. عددی که دو بیت به راست شیفت داده میشه یعنی تقسیم بر 4 میشه (توی این مثال عدد اول 26 بود که بر 4 تقسیم شد و جواب شد 6)

در نتیجه شما میتونید به جای شیفت از ضرب استفاده کنید.

 

خب کاربردش توی برنامه نویسی میکرو چیه؟

از این رو که توی برنامه نویسی میکرو کنترلر ها ما باید به صورت مستقیم با بیت ها کار کنیم باید بتونیم با یه روشی توی زبان سی اون ها رو دست کاری کنیم.

یه چیزی که معمولا همراه شیفت بتی میاد اند و اور بیتی هست.

امیدوارم با And و Or آشنا باشید ولی اگه آشنا نیستید نترسید چون چیز سختی نیست من یه توضیحی میدم اگه متوجه نشدید برید سرچ کنید کاملترش رو بخونید

یه راه ساده برای یادگیری اند و اور اینکه معمولا And رو به صورت ضرب در نظر میگیرند و OR به صورت جمع.

یعنی چی؟

علامت | به معنای OR هست

علامت & به معنای AND است.

شما فرض کنید میگن 1 | 0 خوب بگید 0 با 1 میشه 1

فرض کنید میگن 1 & 0 بگید 0 ضربدر 1 میشه 0

توجه کنید که بیتی هست یعنی اگه گفتن 10 & 01 چی میشه باید تک تک در هم ضرب کنید (یعنی هر بیت رو در بیت متناظر با خودش - بیت اول در بیت اول ، بیت دوم در بیت دوم و...) که اینجا نتیجه میشه 00

فقط یک نکته وجود داره اونم اینه که 1 | 1 نمیشه 2 میشه 1 (آخه گفته بودیم OR یعنی جمع) پس اگه این نکته رو در نظر بگیرید تقریبا شما الان دیگه عملگر های And و Or یا یاد گرفتید

برای تکمیل بحث دو تا مثال میزنم و میرم ادامه میحث شیفت

۰۱۰۱۰۰۱۰ |‌ ۱۰۱۱۰۱۰۰ = ۱۱۱۱۰۱۱۰

۰۱۰۱۰۰۱۰  & ۱۰۱۱۰۱۰۰  = 00010000

امیدوارم که متوجه شده باشید.

 

خب میریم ادامه شیفت

حالا فرض کنید یک متغیر ۳۲ بیتی دارید و میخواهید بیت پنجم اون رو یک کنید. چطور این کار رو میکنید؟ (فرض بر این است که ما مقدار فعلی متغیر رو نمیدونیم!!‌ مثلا فرض کنید این متغیر رو از ورودی خواندیم.

خب کاری نداره این کار رو با OR کردن انجام میدیم

اگه اسم متغیر a باشه خواهیم داشت:

a = a | 0b10000;

در این صورت بیت پنجم این متغیر اگه یک بوده باشه که تغییری نمیکنه (چون اور کردیم) اما اگه صفر بوده یک میشه.

یه راه دیگه اینکار که دو تا مزیت داره استفاده از شیفت هست.

ببینید زبان سی از باینری پشتیبانی نمیکنه و این کامپایلر های میکرو ها هست که باینری رو ساپورت کردن یه نکته دیگه ای هم هست. ما توی این مثال گفتیم بیت ۵ رو یک کنید اگه همین مقدار ۵ توی متغیر دیگه ای بود اون موقع چطوری میخواستید بنویسیدش؟ مثلا میگفتیم متغیر a و b را داریم و میخواهیم بیت n ام متغیر a را یک کنیم که مقدار n در متغیر b است. دیگه نمیشد :/

پس استفاده از شیفت مزیت های خودش رو داره

در این حالت که میخواهیم بیت n ام متغیر a رو یک کنیم باید ابتدا یک عدد باینری بسازیم که بیت n ام اش یک باشه بعد اون رو با مقدار a اور کنیم.

به این صورت 

a = a | 1 << n;

در تکه کد بالا ابتدا عدد یک رو به مقدار n به سمت چپ شیفت میدیم و بعدش با a  اور میکنیم. اگه بخوایم مثال قبل رو باز نویسی کنیم باید به n عدد ۵ بدیم که در این صورت خواهیم داشت:

a = a | 1 << 5;

خب تا اینجا امیدوارم یاد گرفته باشید. تا اینجا فهمیدیم که چطور میشه یک بیت خاص رو توی یک متغیر با استفاده از شیفت و OR یک کرد.

حالا میخوایم یاد بگیریم که چطور میشه یک بیت خاص رو توی یک متغیر صفر کرد؟

شاید فکر کنید این هم مثل اون میمونه ولی نه یه خورده سخت تره

فقط اول کار جلوی یک اشتباه رو بگیرم

ممکنه فکر کنید که توی OR به جای یک صفر میزاریم. اینجوری:

a = a | 0 << n;

به نظرتون مشکلش چیه؟ مشکل اینه که توی OR همه صفر ها نادیده گرفته میشن یعنی بی تاثیرن در نتیجه این خود a رو به ما میده

پس از همین الان باید به فکر AND باشیم چون AND هست که میتونه صفر کنه (هر عدد (توی اینجا صفر یا یک)‌ ضربدر ۰ میشه ۰) 

برای اینکه باقی بیت ها دست نخوره باید عددی که مینویسیم اینجوری باشه: بیت n ام که میخواهیم صفر کنیم رو صفر بزاریم بقیه رو یک بزاریم

مثلا فرض کنید میخواهیم بیت ۵ ام متغیر هشت بیتی a رو صفر کنیم. داریم:

a = a & 11101111;

این تکه کد بیت ۵ ام رو صفر میکنه و به بقیه بیت ها کاری نداره.

حالا اگه بخواهیم این رو هم به صورت شیفت بنویسیم باید چیکار کنیم؟

برای این کار باید از یک عملگر بیتی دیگه کمک بگیریم که باید معروفیش کنم. ساده است خیلی ساده است.

عملگر نقیض بیتی یا نات بیتی (Not) این عملگر میاد و تک تک بیت ها رو برعکس میکنه یعنی صفرها به یک و یک ها به صفر تبدیل میشن.

علامتش توی سی ‍‍~ هست. کلید اول کیبورد کنار عدد ۱ هست.

مثال:

‍~00110101 = 11001010

حالا این توی صفر کردن یک بیت خاص توی یک متغیر به کمک عملگر های شیفت و اند چه کمکی میکنه؟

ما گفتیم برای صفر کردن بیت ۵ از متغیر a مینویسیم:

a = a & 11101111;

حالا میخوایم اون عدد رو به صورت شیفت بنویسیم

قبول دارید که ما میتونیم اون عدد را به صورت زیر بنویسیم:

a = a & ~(00010000);

خب احتمالا فهمیدید میخوایم چیکار کنیم.

درسته حالا ما میتونیم عبارت داخل پرانتز رو به صورت شیفت بنویسیم.

یعنی به این صورت:

a = a & ~(1 << 5);

امیدوارم که متوجه شده باشید که چی شد!!

به عنوان نکته آخر: ما میتونیم اند و اور بیتی رو هم مثل دیگر عملگر های زبان سی ساده بنویسیم. یعنی کد بالا میتونه برای سادگی در نوشتن به صورت زیر هم نوشته بشه

a &= ~(1 << 5);

که احتمالا اینارو توی کد ها بیشتر میبینید.

من سعی کردم تامطالب رو جوری بیان کنم که خوب متوجه بشید!
اما اگر بازم براتون جای سوال داره! میتونم در حد توانم کمکتون کنم!
 
فعلا
یا علی مدد...!