84 / 90

C++ Preprocessor and Macros

C++ preprotsessor va makroslar

Nomidan ko'rinib turibdiki, C++ preprotsessorlari dasturimizni kompilyatsiya qilishdan oldin o'zgartiradigan (oldindan ishlov beradigan) vositalardir.

Preprotsessorlar kod o'zgarishini boshqarish uchun preprotsessor ko'rsatmalaridan foydalanadilar. Masalan,

example.cpp
#include <iostream>

Bu erda #include - <iostream> sarlavha fayli tarkibini kompilyatsiya qilishdan oldin dasturimizga kiritadigan preprotsessor direktivasi.

Working of C++ preprocessor

Working of C++ preprocessor in the compilation process

Preprotsessor direktivalari

C++ da barcha preprotsessor direktivalari # belgisi bilan boshlanadi. Masalan, #include , #define , #if va boshqalar.

C++ preprotsessorlarining umumiy ilovalaridan ba'zilari:

  • #include - to include header files
  • #define - to define macros
  • #if - to provide conditional compilation

Keling, ushbu preprotsessor direktivalarining har biri bilan batafsil tanishib chiqamiz.

#include Preprocessor Directive

#include direktivasi dasturimizga sarlavhali fayllarni kiritish uchun ishlatiladi. Masalan,

example.cpp
#include <cmath>

Bu erda cmath sarlavha faylidir. #include direktivasi preprotsessorga yuqoridagi kod qatorini cmath sarlavha fayli mazmuni bilan almashtirishni aytadi.

Shuning uchun pow() va sqrt() kabi funksiyalardan foydalanish uchun #include <cmath> dan foydalanishimiz kerak.

Shuningdek, biz #include direktivasi yordamida o'z shaxsiy sarlavha fayllarimizni yaratishimiz va ularni dasturimizda ishlatishimiz mumkin. Masalan,

example.cpp
#include "path_to_file/my_header.h"

Bu erda biz dasturimizga my_header.h nomli maxsus sarlavha faylini kiritdik.

Shunday qilib, biz kattaroq dasturni bir nechta fayllarga ajratishimiz mumkin.

#define Preprocessor Directive

#define direktivasi bizning dasturlarimizda ishlatilishi mumkin bo'lgan preprotsessor o'zgaruvchilarini "aniqlash" uchun ishlatiladi. Masalan,

example.cpp
#define PI 3.1415   // pi qiymati

Endi biz dasturimizda PI dan foydalansak, u 3.1415 bilan almashtiriladi.

Bu erda PI makro sifatida tanilgan. Makros - bu nom berilgan kodning bir qismi.

1-misol: C++ #define

example.cpp
#include <iostream>

// PI nomli makro yarating
// 3.1415 qiymati bilan
#define PI 3.1415

using namespace std;

int main() {

    double radius, area;
    
    cout << "Enter the radius: ";
    cin >> radius;

    // doira maydonini hisoblash uchun PI dan foydalaning
    area = PI * radius * radius;
    cout << "Area = " << area;
    
    return 0;
}

Chiqish

kod
Enter the radius: 4
Area = 50.264

Funksiyaga o'xshash makroslar

Funksiya kabi ishlaydigan makroslarni yaratish uchun #define dan ham foydalanishimiz mumkin. Masalan,

example.cpp
#define circleArea(r) (3.1415 * r * r)

Keling, ishlaydigan misolni olaylik:

example.cpp
#include <iostream>
#define PI 3.1415

// doira maydonini hisoblaydigan makro
// va "r" parametrini oladi
#define circle_area(r) (PI * r * r)

using namespace std;

int main() {
    
    double radius = 2.5;

    // circle_area() makrosini chaqiring
    // argument sifatida radiusni o'tkazing
    cout << "Area = " << circle_area(radius);
    
    return 0;
}

Chiqish

kod
Area = 19.6344

Bu erda circleArea(radius); kodi 3.1415 * 2.5 * 2.5 ga kengayadi.

[!NOTE] Funksiyaga o'xshash makroslardan ko'ra funksiyalardan foydalangan ma'qul, chunki makroslar xatoga ko'proq moyil bo'ladi.

#if Preprocessor Directive

#if direktivasi oldindan protsessorga ma'lum shartlarga qarab kod blokini kiritish yoki kiritmaslikni ko'rsatish uchun ishlatiladi.

Bundan tashqari, bir nechta shartlarda #else va #elif direktivalari bilan birgalikda foydalanish mumkin.

Demak, #if , #else va #elif direktivalari C++ tilidagi if...else operatorlariga juda oʻxshash va bitta katta farq bilan.

if...else operatorlari kod bloki bajarilishi kerakmi yoki yo'qligini tekshirish uchun bajarish vaqtida sinovdan o'tkaziladi.

Boshqa tomondan, shartli direktivalar dasturga kod blokini kiritish yoki kiritmaslik to'g'risida qaror qabul qilish uchun kompilyatsiya qilishdan oldin preprotsessor tomonidan sinovdan o'tkaziladi. Mana oddiy misol,

example.cpp
#include <iostream>  

// 3 qiymatiga ega NUMBER ta makro yarating
#define NUMBER 3 

using namespace std;

int main() {
    
    // tekshirish uchun #if direktivasidan foydalaning
    // agar NUMBER 0 dan katta bo'lsa
    #if (NUMBER > 0) 
        cout << NUMBER << " is greater than 0.";
    #else
        cout << NUMBER << " is less than 0.";
    #endif         
 
    return 0;    
}

Chiqish

kod
3 is greater than 0.

Bu erda #endif direktivasi #if va #else direktivalarining bajarilishini ko'rsatish uchun ishlatiladi. Biroq, if...else iboralari ishlash vaqtida kodning qaysi qismini bajarish kerakligini hal qilish uchun preprotsessor ko'rsatmalariga qaraganda afzalroqdir. Shunga qaramay, #if direktivalari ko'proq qo'llanilishi mumkin bo'lgan bir nechta holatlar mavjud:

  • Operatsion tizimga qarab turli kodlardan foydalanish (platformaga xos kod).
  • Faqat disk raskadrovka tuzilmalarida ishlaydigan disk raskadrovka kodlarini (masalan, disk raskadrovka xabarlarini chop etish) kiritish.
  • Muayyan sharoitlarga qarab xususiyatlarni yoqish va o'chirish uchun.
  • Dasturiy ta'minotning ma'lum versiyalari yoki nashrlariga xos bo'lgan kodni kiritish (versiyaga xos kod).

2-misol: Platformaga xos C++ kodi

example.cpp
#include <iostream>
using namespace std;

int main() {
    
    // Windowsda ishlayotgan bo'lsa, o'z ichiga oladi
    #ifdef _WIN32
        cout << "Hello from Windows!" << endl;
    
    // Linuxda ishlayotgan bo'lsa, o'z ichiga oladi
    #elif __linux__
        cout << "Hello from Linux!" << endl;
    
    // boshqa tizimda ishlayotgan bo'lsa, o'z ichiga oladi
    #else
        cout << "Hello from an unknown platform!" << endl;
    #endif

    return 0;
}

Chiqish

kod
Hello from Linux!

Bu shartli kompilyatsiya yordamida platformaga xos kodning namunasidir.

Bu yerga,

-_WIN32 - Windows platformalarida Microsoft Visual C++ kompilyatori tomonidan belgilangan makros

  • __linux__ - a macro defined by GNU C Compiler on Linux systems
  • #ifdef - a variant of #if which checks if a macro has been defined or not

_WIN32 va __linux__ makroslari dastur ishlayotgan tizimni aniqlash uchun ishlatiladi.

Oldindan belgilangan makrolar

Bu erda C++ dasturlashda tez-tez ishlatiladigan oldindan belgilangan makroslar mavjud.

Ibratli qiymat __DATE__ Joriy sanani o'z ichiga olgan qator. __FILE__ Hozirda bajarilayotgan dasturning fayl nomini o'z ichiga olgan qator. __LINE__ Joriy satr raqamini ifodalovchi butun son. __TIME__ Joriy vaqtni (GMT) o'z ichiga olgan qator.

[!NOTE] Bular oldindan belgilangan makroslar bo'lgani uchun biz ulardan foydalanish uchun #define direktivasidan foydalanishimiz shart emas.

3-misol: Oldindan belgilangan makroslar

example.cpp
#include <iostream>
using namespace std;

int main() {

  // joriy vaqtni chop eting
  cout << "Current time: " << __TIME__;

  return 0;
}

Chiqish

kod
Current time: 04:23:31

Ushbu dastur joriy vaqtni (GMT) __TIME__ makrosidan foydalanib chop etadi.