C Preprosessor tushunchasi

Dastur matni va preprosessor. C tilida matnli fayl shaklida tayyorlangan dastur uchta qayta ishlash bosqichlaridan o’tadi. Matnni preprosessor direktivalari asosida o’zgartilishi. Bu jarayon natijasi yana matnli fayl bo’lib preprosessor tomonidan bajariladi. Kompilyasiya - bu jarayon natijasi mashina kodiga o’tkazilgan obyektli fayl bo’lib, kompilyator tomonidan bajariladi. Bog’lash - bu jarayon natijasi to’la mashina kodiga o’tkazilgan bajariluvchi fayl bo’lib, bog’lagich (komponovshik) tomonidan bajariladi. Preprosessor vazifasi dastur matnini preprosessor direktivalari asosida o’zgartirishdir. Masalan define direktivasi dasturda bir jumlani ikkinchi jumla bilan almashtirish uchun ishlatiladi. Bu direktiva umumiy ko’rinishi quyidagicha:

#define <almashtiruvchi ifoda> <almashinuvchi ifoda>

Bu direktiva bajarilganda dastur matnidagi almashtiruvchi ifodalar almashinuvchi ifodalarga almashtiriladi. Agar dasturda quyidagi matn mavjud bo’lsin:

#define EULER 2.718282
double mix = EULER
d = alfa*EULER

Preprosessor bu matnda har bir EULER konstantani uning qiymati bilan almashtiradi, va natijada quyidagi matn hosil bo’ladi.

double mix = 2.718282
d = alfa*2.718282 

Matndagi almashtirishlarni #undefine direktivsi orqali rad etish mumkindir.

Masalan:

#define E 2
#undefine E
#define E ‘A’

include direktivasi ikki ko’rinishda ishlatilishi mumkin. #include fayl nomi direktivasi dasturning shu direktiva o’rniga qaysi matnli fayllarni qo’shish kerakligini ko’rsatadi. #include <fayl nomi> direktivasi dasturga kompilyator standart bibliotekalariga mos keluvchi sarlavhali fayllar matnlarini qo’shish uchun mo’ljallangandir. Bu fayllarda funksiya prototipi, turlar, o’zgaruvchilar, konstantalar ta’riflari yozilgan bo’ladi. Funksiya prototipi funksiya qaytaruvchi tur, funksiya nomi va funksiyaga uzatiluvchi turlardan iborat bo’ladi. Misol uchun cos funksiyasi prototipi quyidagicha yozilishi mumkin: double cos(double). Agar funksiya nomidan oldin void turi ko’rsatilgan bo’lsa bu funksiya hech qanday qiymat qaytarmasligini ko’rsatadi. Shuni ta’kidlash lozimki bu direktiva dasturga standart biblioteka qo’shilishiga olib kelmaydi. Standart funksiyalarning kodlari bog’lash ya’ni aloqalarni tahrirlash bosqichida, kompilyasiya bosqichidan so’ng amalga oshiriladi. Kompilyasiya bosqichida sintaksis xatolar tekshiriladi va dasturda bunday xatolar mavjud bo’lmasa, standart funksiyalar kodlarisiz mashina kodiga o’tkaziladi. Sarlavhali fayllarni dasturning ixtiyoriy joyida ulash mumkin bo’lsa ham, bu fayllar odatda dastur boshida qo’shish lozimdir. Shuning uchun bu fayllarga sarlavhali fayl (header file) nomi berilgandir. Dastur matnini kompilyasiya qilish. Dastur kodini bajariluvchi faylga o’tkazish uchun kompilyatorlar qo’llaniladi. Kompilyator qanday chaqiriladi va unga dastur kodi joylashgan joyi haqida qanday xabar qilinadi, bu konkret kompilyatorga bog’liqdir. Bu ma’lumotlar kompilyatorning dokumentasiyasida berilgan bo’ladi. Dastur kodi kompilyasiya qilinishi natijasida ob’ektli fayl hosil qilinadi. Bu fayl odatda .obj kengaytmali bo’ladi. Lekin bu hali bajariluvchi fayl degani emas. Obyektli faylni bajariluvchi faylga o’girish uchun yig’uvchi dastur qo’llaniladi. Yig’uvchi dastur yordamida bajariluvchi faylni hosil qilish. C tilida dasturlar odatda bir yoki bir nechta ob’ektli fayllar yoki bibliotekalarni komponovka qilish yordamida hosil qilinadi. Biblioteka deb bir yoki bir nechta komponovka qilinuvchi fayllar to’plamiga aytiladi. C ning barcha kompilyatorlari dasturga qo’shish mumkin bo’lgan funksiyalar (yoki proseduralar) va sinflardan iborat biblioteka hosil qila oladi. Funksiya – bu ayrim xizmatchi amallarni, masalan ikki sonni qo’shib, natijasini ekranga chiqarishni bajaruvchi dastur blokidir. Sinf sifatida ma’lumotlar to’plami va ularga bog’langan funksiyalarni qarash mumkin. Funksiyalar va sinflar haqidagi ma’lumotlar keyingi mavzularda batafsil berilgan. Demak, bajariluvchi faylni hosil qilish uchun quyida keltirilgan amallarni bajarish lozim: Avval .spp kengaytmali dastur kodi hosil qilinadi; Dastur kodini kompilyasiya qilish orqali .obj kengaytmali obyektli fayl tuziladi; Bajariluvchi faylni hosil qilish maqsadida .obj kengaytmali fayli zaruriy bibliotekalar orqali komponovka qilinadi. Fayllardan matnlar qo’shish. Fayldan matn qo’shish uchun uch shaklga ega bo’lgan # include operatori qo’llaniladi:

# include <fayl nomi>
# include "fayl nomi"
# include makros nomi

Makros nomi #define direktivasi orqali kiritilgan preprosessor identifikatori yoki makros bo’lishi mumkin. Agar birinchi shakl qo’llanilsa preprosessor qo’shilayotgan faylni standart bibliotekalardan izlaydi. Agar ikkinchi shakl qo’llanilsa preprosessor foydalanuvchining joriy katalogini ko’rib chiqadi va bu katalogda fayl topilmasa standart sistemali kataloglarga murojaat qiladi. Agar programmada bir necha funksiyalardan foydalanilsa, funksiyalar ta’rifi, tanasi bilan birga alohida fayllarda saqlash qulaydir. Hamma funksiyalar tanasiga va main() funksiyasi tanasiga chaqirilayotgan funksiyalar prototiplari joylashtirilsa, programma tanasida funksiyalarni ixtiyoriy joylashtirish mumkin. Bu holda programma faqat prosessor komandalaridan ham iborat bo’lishi mumkin. S standarti bo’yicha .h suffiksi bibliotekaga tegishli funksiyalarning prototiplari hamda, turlar va konstantalar ta’rifi joylashgan fayllarni ko’rsatadi. Bunday fayllarni sarlavhali fayllar deb ataladi. Kompilyator bibliotekalari bilan ishlashga mo’ljallangan sarlavhali fayllar ro’yxati til standartida ko’rsatilgan bo’lib bu fayllar nomlari tilning xizmatchi so’zlari hisoblanadi. Quyida shu standart fayllar nomlari keltirilgan:

  • Assert.h – programma diagnostikasi.
  • Type.h – simvollarni o’zgartirish va tekshirish.
  • Erruo – xatolarni tekshirish.
  • Float.h – haqiqiy sonlar bilan ishlash.
  • Limits.h – butun sonlarning chegaralari.
  • Locate.h – milliy muhitga moslash.
  • Match.h – matematik hisoblashlar.
  • Setjump.h – nolokal o’tishlar imkoniyatlari.
  • Signal.h – g’ayrioddiy holatlar bilan ishlash.
  • Stdarg.h – uzgaruvchi sonli parametrlarni qo’llash.
  • Stddef.h – qo’shimcha ta’riflar.
  • Stdlib.h – xotira bilan ishlash.
  • String.h – simvolli qatorlar bilan ishlash.
  • Time.h – sana va vaqtni aniqlash.

Turbo C va Borland C++ kompilyatorlarida grafik biblioteka bilan bog’lanish uchun graphic.h – sarlavhali fayl qo’llaniladi.

Shartli direktivalar. Shartli direktiva quyidagi ko’rinishga egadir:

#if butun sonli ifoda.
tekst_1
#else 
tekst_2
#endif
#else 
tekst_2 qismi ishlatilishi shart emas.

Direktiva bajarilganda #if dan so’ng yozilgan butun sonli ifoda qiymati hisoblanadi. Agar bu qiymat 0 dan katta bo’lsa tekst_1 kompilyasiya qilinayotgan matnga qo’shiladi, aksincha tekst_2 qo’shiladi. Agar #else direktivasi va tekst_2 mavjud bo’lmasa bu direktiva o’tkazib yuboriladi. #ifdef identifikator direktivasida #define direktivasi yordamida identifikator aniqlanganligi tekshiriladi. Agar identifikator aniqlangan bo’lsa tekst_1 bajariladi. #ifndef identifikator direktivasida aksincha shart rost hisoblanadi agar identifikator aniqlanmagan bo’lsa. Dasturga ulash mo’ljallangan fayllarning har biriga bitta fayl ulanish mo’ljallangan bo’lsa, bu fayl bir necha marta dasturga ulanib qoladi. Bu qayta ulanishni oldini olish uchun standart fayllar yuqorida ko’rilgan direktivalar yordamida himoya qilingandir. Bu himoya usuli quyidagicha bo’lishi mumkin.

/* filename Nomli fayl */
/* FILENAME aniqlanganligini tekshirish */
# indef FILE_NAME
… /* Ulanayotgan fayl teksti
/* Ta’rif
#define FILE_NAME
#endif

Tarmoqlanuvchi shartli direktivalar yaratish uchun quyidagi direktiva kiritilgan:

#elif butun_sonli_ifoda

Bu direktiva ishlatilgan tekst strukturasi:

#if shart
tekst
#elif 1_ifoda
1_tekst
#elif 2_ifoda
2_tekst
…
#else
tekst
#endif

Preprosesssor avval #if direktivasidagi shartni tekshiradi. Agar shart 0 ga teng bo’lsa 1_ifoda hisoblanadi agar u ham 0 bo’lsa 2_ifodani hisoblaydi va hokazo. Agar hamma ifodalar 0 bo’lsa else uchun ko’rsatilgan tekst ulanadi. Agar biror ifoda 0 dan katta bo’lsa shu direktivada ko’rsatilgan tekst ulanadi. Unar defined operasiyasi. Tekst shartli qayta ishlanganda unar preprosessor amali defined operand amalidan foydalanish mumkin. Quyidagi if defined ifodasi #ifdef operand ifodasiga ekvivalentdir. Bu ko'rinishda defined afzalligi bilinmaydi. Misol uchun biror tekst kompilyatorga Y identifikatori aniqlangan, N bo’lsa aniqlanmagan holda uzatish lozim bulsin. U holda preprosessor direktivasi quyidagicha yoziladi:

#if defined Y&&!defined N
tekst
#endif

Bu direktivani quyidagicha ham yozish mumkin.

#ifdef Y
#ifndef N
tekst
#endif
#endif

Yordamchi direktivalar. Satrlarni nomerlash uchun quyidagi direktivadan foydalanish mumkin:

# line konstanta

Direktiva fakat satr nomeri emas, fayl nomini ham o’zgartirishi mumkin:

#line konstanta “fayl nomi”

Odatda bu direktiva kam ishlatiladi. Quyidagi direktiva leksemalar ketma-ketligi orqali ko’rsatilgan shaklda diagnostik ma’lumotlar berilishiga olib keladi.

# error leksemalar ketma-ketligi.

Misol uchun NAME preprosessor o’zgaruvchisi aniqlangan bo’lsin:

#define NAME 5

Dasturda bu o’zgaruvchi qiymatini tekshirib, 5 ga teng bo’lmagan holda ma’lumot berish uchun quyidagi direktivadan foydalaniladi:

#if (NAME! = 5)
#error NAME 5 ga teng bo’lishi kerak
#Xech qanday xizmat bajarmaydigan direktiva: