P01NT
0x02 الأساسيات 03/19

المتغيرات والثوابت

تعريف المتغيرات وقواعد تسميتها، والثوابت عبر const و#define، والفرق الجوهري بينهما وقت الترجمة وفي الذاكرة.

· 4 دقائق قراءة · 671 كلمة
المحتويات

بسم الله الرحمن الرحيم.

في هذا المقال سنتعرف على تعريف المتغيرات وخطوات تعريفها وقواعد تسميتها، بالإضافة إلى تعريف الثوابت وأنواعها وطرق تعريفها، وفي النهاية سنوضح الفرق بين المتغيرات والثوابت.

أولاً: المتغيرات (Variables)

تعريفها: هي مكان يُحجز في الذاكرة (RAM) لتخزين قيمة معينة أثناء تشغيل البرنامج.

ملاحظة دقيقة: قيمة المتغير المحلي تُحرَّر مساحتها من الـ stack عند انتهاء الدالة، لكن القيمة نفسها قد تبقى في الذاكرة الفعلية حتى تُستبدل بقيم أخرى. وهذا المفهوم مهم جداً في الهندسة العكسية — فالمحلل يبحث أحياناً عن قيم قديمة لم تُمسح عمداً.

خطوات تعريف المتغير

  1. تحديد نوع البيانات (وسنشرحه في المقال القادم إن شاء الله).
  2. تسمية المتغير: يجب أن يكون الاسم فريداً (unique) ويتبع قواعد التسمية أدناه.
  3. تخصيص قيمة ابتدائية: خطوة اختيارية.

صيغة تعريف المتغير

dataType varName = value;

قواعد تسمية المتغيرات

  • يبدأ الاسم بحرف أو علامة _ (underscore).
  • يمكن أن يحتوي على الأحرف (a-z, A-Z) والأرقام (0-9) وعلامة _.
  • لا يُسمح باستخدام الكلمات المحجوزة (مثل int, return).
  • حساسية حالة الأحرف: Age و age متغيران مختلفان.

مثال

#include <stdio.h>

int main() {
    int age = 25;           // متغير من النوع int
    float height = 5.8;     // متغير عشري
    char grade = 'A';       // متغير حرفي
    char name[] = "Ali";    // متغير نصي (مصفوفة من الأحرف)

    printf("Age: %d\n", age);
    printf("Height: %.1f\n", height);
    printf("Grade: %c\n", grade);
    printf("Name: %s\n", name);

    return 0;
}

الناتج:

Age: 25
Height: 5.8
Grade: A
Name: Ali

ثانياً: الثوابت (Constants)

تعريفها: تشبه المتغيرات في استخداماتها، لكنها عكسها في أهم خاصية — قيمتها لا تتغير أثناء تنفيذ البرنامج.

أنواع الثوابت

النوعالوصفمثال
ثوابت رقمية (Numeric)أعداد صحيحة أو عشرية10, -5, 3.14
ثوابت حرفية (Character)حرف واحد بين علامتي اقتباس مفردة'A', 'b'
ثوابت نصية (String)نصوص بين علامتي اقتباس مزدوجة"Hello"
ثوابت رمزية (Symbolic)تُعرّف بـ const أو #defineMAX_SIZE

طريقتان لتعريف الثوابت

1. باستخدام const

const dataType constName = value;

ملاحظة هامة: يجب وجود قيمة عند تعريف الثابت.

2. باستخدام #define

#define constName value

مثال

#include <stdio.h>

#define MAX_SIZE 100  // ثابت رمزي باستخدام #define

int main() {
    const float PI = 3.14;  // ثابت باستخدام const

    printf("Value of PI: %.2f\n", PI);
    printf("Maximum Size: %d\n", MAX_SIZE);

    // محاولة تغيير قيمة ثابت ستؤدي إلى خطأ:
    // PI = 3.14159;     // المترجم يمنع الكتابة على const مباشرة
    // MAX_SIZE = 200;   // #define ليست متغيراً أصلاً!

    return 0;
}

الناتج:

Value of PI: 3.14
Maximum Size: 100

الفرق بين const و #define

const#define
التعريفمتغير ثابت لا تتغير قيمته في وقت التنفيذماكرو يُستبدل نصياً أثناء الترجمة
المعالجةمرحلة التنفيذ (runtime)مرحلة الترجمة (compile time)
النطاقيتبع قواعد نطاق المتغيرات (محلي/عام)لا نطاق له — يُستبدل في كل مكان يُستخدم فيه
النوعيتطلب تحديد النوع (أمان أكبر)لا يتطلب نوعاً (قد يسبب أخطاء)

نقطة مهمة لمجال RE:

  • #define يُستبدل قبل الترجمة — سترى قيمته مضمنة مباشرة في التعليمات (immediate) أو في قسم .rodata/.rdata، ولا يظهر لها أي أثر كمتغير.
  • const تُخزَّن فعلياً في الذاكرة كمتغير عادي، لكن المترجم يمنع الكتابة عليها مباشرة.
  • خلاصة مهمة: const في لغة C ليست ثابتاً حقيقياً وقت الترجمة — هي متغير للقراءة فقط. ويمكن تعديلها فعلياً عبر المؤشرات (وهذا ما يهم المحلل لاحقاً عندما يرى كوداً يكتب على ذاكرة const).
  • الثوابت الحقيقية المترجمة تُكتب بـ #define أو enum.

الفرق بين المتغيرات والثوابت

المتغيراتالثوابت
القيمةيمكن تغييرها أثناء التنفيذلا يمكن تغييرها أثناء التنفيذ
التخزينفي الـ stack أو الـ heap (بيانات ديناميكية)مضمنة في التعليمات أو .rodata/.rdata
التعريفint x = 5;const int x = 5; أو #define X 5
الاستخدامللقيم التي تتغيرللقيم الثابتة في سياق البرنامج

تمرين عملي (للمقالات السابقة معاً)

طبّق الخطوات بنفسك وراقب الفرق الحقيقي:

#define LIMIT 100

int main(void){
    const int x = 42;
    int y = LIMIT;
    return 0;
}
gcc -E test.c -o test.i    # شاهد LIMIT تختفي وتصبح 100 في كل مكان
gcc -S test.i -o test.s    # شاهد قيمة 42 و 100 في تعليمات mov

لاحظ: LIMIT تختفي تماماً بعد المعالجة المسبقة، بينما x تبقى متغيراً حقيقياً في الـ assembly.


ملاحظة ختامية: لا فائدة من الفهم دون تطبيق. جرّب كل مثال بيدك، وستجد الفرق يثبت في ذهنك. ورأيكم مهم — سواء نقد للتحسين أو مدح للاستمرار.