C: العمليات على البتات

العمليات على البتات كالتحكم في صف من مفاتيح الإضاءة — كل مصباح يقابل بتًا واحدًا، ويمكنك تشغيل أو إيقاف أو قلب أي مصباح دون التأثير على البقية.

1. مراجعة النظام الثنائي

تمثل الحواسيب جميع البيانات داخليًا بالنظام الثنائي. بايت واحد = 8 بتات، كل بت إما 0 أو 1.

TEXT 📖 للعرض فقط
Decimal 42  =  Binary 00101010
Decimal 255 =  Binary 11111111

الأعداد الصحيحة الموقّعة تستخدم تمثيل مكمل الاثنين: البت الأعلى هو بت الإشارة، 0 للموجب، و1 للسالب.

C
Decimal  5  =  00000101
Decimal -5  =  11111011  (two's complement)

2. عاملات البت الستة

العامل الاسم القاعدة
& AND على البتات النتيجة 1 فقط عندما يكون كلا البتين 1
| OR على البتات النتيجة 1 عندما يكون أحد البتين على الأقل 1
^ XOR على البتات النتيجة 1 عندما يختلف البتان
~ NOT على البتات 0 يصبح 1، و1 يصبح 0
<< إزاحة لليسار يزيح البتات لليسار، يملأ البتات الدنيا بـ 0
>> إزاحة لليمين يزيح البتات لليمين، يملأ البتات العليا ببت الإشارة (موقّع) أو 0 (غير موقّع)

(1) AND على البتات (&)

TEXT 📖 للعرض فقط
  1010  (10)
& 1100  (12)
------
  1000  (8)

الاستخدامات: تصفير بتات محددة، التحقق مما إذا كانت بتات معينة تساوي 1.

(2) OR على البتات (|)

C
  1010  (10)
| 1100  (12)
------
  1110  (14)

الاستخدامات: ضبط بتات محددة إلى 1.

(3) XOR على البتات (^)

TEXT 📖 للعرض فقط
  1010  (10)
^ 1100  (12)
------
  0110  (6)

خصائص: a ^ a = 0، a ^ 0 = a. XOR قابل للعكس — تطبيقه مرتين بنفس القيمة يعيد الأصل.

(4) NOT على البتات (~)

C
~ 00101010  (42)
= 11010101  (-43, two's complement)

للأعداد غير الموقّعة: ~0 = 255 (8 بت)، ~0 = 0xFFFFFFFF (32 بت).

(5) الإزاحة لليسار (<<)

TEXT 📖 للعرض فقط
5 << 2
= 00000101 << 2
= 00010100
= 20

الإزاحة لليسار بمقدار n تكافئ الضرب في 2^n. 5 << 2 = 5 * 4 = 20.

(6) الإزاحة لليمين (>>)

C
20 >> 2
= 00010100 >> 2
= 00000101
= 5

الإزاحة لليمين بمقدار n تكافئ القسمة على 2^n (تُقرّب نحو الصفر).

⚠️ ملاحظة: إزاحة الأعداد السالبة الموقّعة لليمين تملأ البتات العليا بـ 1 (إزاحة حسابية)، مما قد ينتج نتائج غير متوقعة. يُنصح بإزاحة القيم غير الموقّعة فقط.


3. عمليات البت الأربع الأساسية

(1) ضبط بت (إلى 1)

TEXT 📖 للعرض فقط
flags |= (1 << n);

يضبط البت n إلى 1، مع ترك جميع البتات الأخرى دون تغيير.

(2) تصفير بت (إلى 0)

C
flags &= ~(1 << n);

يُنتج ~(1 << n) قناعًا كله 1 ما عدا 0 في الموضع n. AND يُصفّر تلك البت فقط.

(3) قلب بت

TEXT 📖 للعرض فقط
flags ^= (1 << n);

عملية XOR: 0^1=1، 1^1=0، مما ينفذ القلب بشكل مثالي.

(4) فحص بت

C
if (flags & (1 << n)) {
}

إذا كانت البت n تساوي 1، فالنتيجة غير صفرية؛ وإذا كانت 0، فالنتيجة صفر.

▶ مثال

C
#include <stdio.h>

void print_bits(unsigned char val) {
    for (int i = 7; i >= 0; i--) {
        printf("%d", (val >> i) & 1);
    }
    printf("\n");
}

int main(void) {
    unsigned char flags = 0;

    flags |= (1 << 3);
    printf("Set bit 3: ");
    print_bits(flags);

    flags |= (1 << 5);
    printf("Set bit 5: ");
    print_bits(flags);

    flags &= ~(1 << 3);
    printf("Clear bit 3: ");
    print_bits(flags);

    flags ^= (1 << 5);
    printf("Toggle bit 5: ");
    print_bits(flags);

    flags ^= (1 << 7);
    printf("Toggle bit 7: ");
    print_bits(flags);

    if (flags & (1 << 7)) {
        printf("Bit 7 is 1\n");
    }

    return 0;
}
▶ جرّب الكود
TEXT 📖 للعرض فقط
Set bit 3: 00001000
Set bit 5: 00101000
Clear bit 3: 00100000
Toggle bit 5: 00000000
Toggle bit 7: 10000000
Bit 7 is 1

4. تقنيات القناع

القناع هو تركيبة محددة مسبقًا من البتات تُستخدم لاستخراج أو تعديل حقول بت محددة ضمن البيانات.

(1) استخراج البتات الدنيا

C
unsigned int val = 0xABCD;
unsigned int low_byte = val & 0xFF;

0xFF قناع يحتفظ بأدنى 8 بتات فقط.

(2) استخراج البتات العليا

TEXT 📖 للعرض فقط
unsigned int high_byte = (val >> 8) & 0xFF;

إزاحة لليمين بـ 8 بتات أولاً، ثم قناع للحصول على أدنى 8 بتات.

(3) دمج القيم

C
unsigned int combined = (high << 8) | low;

دمج بايتين في قيمة 16 بت.

▶ مثال

استخراج قيم ألوان RGB. قيمة اللون 24 بت تحتوي على 8 بتات لكل من الأحمر والأخضر والأزرق:

C
#include <stdio.h>

int main(void) {
    unsigned int color = 0xFF6633;

    unsigned char r = (color >> 16) & 0xFF;
    unsigned char g = (color >> 8) & 0xFF;
    unsigned char b = color & 0xFF;

    printf("Color #FF6633:\n");
    printf("  Red: %d\n", r);
    printf("  Green: %d\n", g);
    printf("  Blue: %d\n", b);

    unsigned int new_color = 0x00;
    new_color |= ((r / 2) << 16);
    new_color |= ((g / 2) << 8);
    new_color |= (b / 2);
    printf("Darkened: #%06X\n", new_color);

    return 0;
}
▶ جرّب الكود
TEXT 📖 للعرض فقط
Color #FF6633:
  Red: 255
  Green: 102
  Blue: 51
Darkened: #7F3319
💡 نصيحة: استخراج ألوان RGB هو تطبيق كلاسيكي للعمليات على البتات. في تطوير الويب، التنسيق #RRGGBB هو في جوهره عدد صحيح 24 بت — الأحمر في البتات 16-23، والأخضر في البتات 8-15، والأزرق في البتات 0-7.


5. أعلام الصلاحيات

صلاحيات ملفات لينكس هي تطبيق كلاسيكي للعمليات على البتات. 9 بتات صلاحية تمثل المالك/المجموعة/الآخرين للقراءة/الكتابة/التنفيذ:

C
rwxr-xr-x = 111101101 = 0755
rw-r--r-- = 110100100 = 0644
C
#include <stdio.h>

#define READ    (1 << 2)
#define WRITE   (1 << 1)
#define EXECUTE (1 << 0)

void show_permission(unsigned char perm) {
    printf("%c", (perm & READ) ? 'r' : '-');
    printf("%c", (perm & WRITE) ? 'w' : '-');
    printf("%c", (perm & EXECUTE) ? 'x' : '-');
}

int main(void) {
    unsigned char owner  = READ | WRITE | EXECUTE;
    unsigned char group  = READ | EXECUTE;
    unsigned char other  = READ | EXECUTE;

    printf("Permissions: ");
    show_permission(owner);
    show_permission(group);
    show_permission(other);
    printf("\n");

    owner &= ~WRITE;
    printf("After removing write: ");
    show_permission(owner);
    show_permission(group);
    show_permission(other);
    printf("\n");

    return 0;
}
TEXT 📖 للعرض فقط
Permissions: rwxr-xr-x
After removing write: r-xr-xr-x

6. حيل عملية على البتات

(1) تبديل متغيرين (بدون متغير مؤقت)

C
a ^= b;
b ^= a;
a ^= b;

المبدأ: خاصية الانعكاس الذاتي لـ XOR. لكن هذا يضر بالقراءة ولا يُنصح به في التطوير الفعلي.

(2) فحص الفردي والزوجي

TEXT 📖 للعرض فقط
if (n & 1) {
}

إذا كانت أدنى بت 1، فالعدد فردي. هذا أسرع من n % 2.

(3) الضرب/القسمة بأسس 2

C
n << 1
n << 2
n >> 1

المترجمات عادةً تحسّن n * 2 إلى إزاحة، لكن الإزاحة آمنة فقط للأعداد الموجبة.

(4) حساب أسس 2

TEXT 📖 للعرض فقط
unsigned int pow2 = 1u << n;

1u << 0 = 1، 1u << 1 = 2، 1u << 8 = 256... الإزاحة أسرع بكثير من pow(2, n).

(5) المحاذاة إلى أس 2

C
unsigned int aligned = (value + mask) & ~mask;

مثلاً، المحاذاة إلى حد 4 بايت: (n + 3) & ~3.

C
#include <stdio.h>

int main(void) {
    int values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (int i = 0; i < 10; i++) {
        int aligned = (values[i] + 3) & ~3;
        printf("%d -> %d\n", values[i], aligned);
    }
    return 0;
}
TEXT 📖 للعرض فقط
0 -> 0
1 -> 4
2 -> 4
3 -> 4
4 -> 4
5 -> 8
6 -> 8
7 -> 8
8 -> 8
9 -> 12

❓ أسئلة شائعة

س لماذا عمليات الإزاحة أسرع من الضرب والقسمة؟
ج الإزاحة تعليمات بوحدة معالجة مركزية بدورة واحدة، بينما الضرب والقسمة يحتاجان دورات ساعة متعددة. لكن المترجمات الحديثة تحسّن تلقائيًا الضرب بأسس 2 إلى إزاحات، فلا حاجة لكتابتها يدويًا.
س هل يمكن استخدام العمليات على البتات مع الأعداد العشرية؟
ج لا. عاملات البت تعمل فقط مع الأنواع الصحيحة. لمعالجة بتات عدد عشري، يجب نسخ بايتاته إلى عدد صحيح باستخدام memcpy.
س ما الخطأ في التبديل بـ XOR؟
ج إذا كان a وb يشيران إلى نفس الذاكرة (نفس المتغير)، فالتبديل بـ XOR سيصفّر القيمة. بالإضافة إلى أن القراءة ضعيفة، والمترجم يحسّن التبديل العادي ليكون فعّالًا بالمثل.

📖 ملخص

📝 تمارين

  1. اكتب دالة تُرجع عدد البتات ذات القيمة 1 في التمثيل الثنائي لعدد صحيح (باستخدام العمليات على البتات، لا القسمة على 2 في حلقة)
  2. اكتب برنامجًا يستخدم العمليات على البتات لضبط سطوع لون RGB (اضرب كل قناة في معامل وأعد الدمج)
  3. اكتب دالة تستخرج البتات من m إلى n من عدد صحيح 32 بت (m < n، العد من البت 0)
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%