Кіріспе

C және C++ тілдерінде құралым

C және C++ бағдарламалау тілдерінде #include күзетшісі, кейде макро күзетшісі, бас файл күзетшісі немесе файл күзетшісі деп аталатын конструкция, #include директивасымен жұмыс істегенде екі рет қосылу проблемасын болдырмау үшін қолданылады. C препроцессоры #include <файл> түріндегі директиваларды бастапқы файлдағы тиісті файлды дискіде іздеп, оның мазмұнын бастапқы файлдың көшірмесіне, яғни аударма бірлігіне ("қосып") көшіріп, осы процесте #include директивасын алмастырады. Осылай қосылатын файлдар әдетте функциялар мен сыныптар немесе құрылымдардың жарияланымдарын қамтитын бас файлдар болып табылады. Егер берілген файлға қатысты #include директивасы компиляция кезінде бірнеше рет пайда болса (мысалы, ол бірнеше басқа бас файлдарда пайда болғандықтан), файл әр жолы қайтадан өңделеді. Дегенмен, егер белгілі бір C немесе C++ тілінің құралымдары екі рет анықталса, нәтижедегі аударма бірлігі жарамсыз болады. #include күзетшілері осындай қате құралымның пайда болуын болдырмайды, олар бас файл алғаш рет қосылғанда препроцессор макросын анықтайды және оның бар екенін анықтап, келесі қосылуларда файлдың мазмұнын жіберіп жібереді. #include күзетшісін бас файлға қосу – осы файлды идемпотент етудің бір жолы. Екі рет қосылумен күресудің тағы бір құралы – #pragma once, ол стандартқа сәйкес болмаса да, C және C++ компиляторларының көпшілігінде қолдауға ие.

"parent.h" файлы

#include "grandparent.h"

# "әже-бабай.h" файлын қосады.

"child.c" файлы

#include "әже-бабай.h"
#include "ата-ана.h"

Мысал

Осы бөлімде бірдей код қолданылады, бірақ #include қорғаулары қосылған. C препроцессоры бас файлдарды өңдейді, оларды қосып, одан әрі рекурсивті түрде қайта өңдейді. Нәтижесінде дұрыс бастапқы файл шығады, біз оны көреміз.

"parent.h" файлы

#include "grandparent.h"

# "әже-бабай.h" файлын қосады.

"child.c" файлы

#include "әже-бабай.h"
#include "ата-ана.h"

Талқылау

Қамқор макросының әртүрлі атау конвенцияларын әртүрлі бағдарламашылар қолдануы мүмкін. Жоғарыда келтірілген мысалдың тағы бір кең таралған түрлері GRANDPARENT INCLUDED, CREATORSNAME YYYYMMDD HHMMSS (тиісті уақыт ақпаратымен ауыстырылған) және UUID-ден жасалған атауларды қамтиды. (Дегенмен, бір астын сызу және үлкен әріппен басталатын атаулар (C және C++) немесе қос астын сызуды қамтитын кез келген атау (тек C++), мысалы, GRANDPARENT H және GRANDPARENT H, тілдік реализация үшін резервтелген және пайдаланушылар оларды қолданбауы керек.) Әрине, әртүрлі бас файлдарда бірдей include guard макросының атауын қайталаудан сақтану маңызды, себебі біріншісінің қосылуы екіншісінің қосылуына кедерес келтіреді, нәтижесінде екінші бас файлдағы кез келген жарияланымдар, сызықтық анықтамалар немесе басқа #include директивалары жоғалып кетуі мүмкін.

Қиындықтар

#include қорғауларының дұрыс жұмыс істеуі үшін, әрбір қорғау әртүрлі алдын ала өңдеуші макросын тексеріп, шартты түрде белгілеуі керек. Сондықтан, #include қорғауларын пайдаланатын жоба, оның include қорғаулары үшін үйлесімді атау жүйесін әзірлеуі керек және оның жүйесі пайдаланатын кез келген үшінші тараптың мәлімдемелерімен немесе кез келген жаһандық түрде көрінетін макростардың аттарымен қақтығысқа түспейтініне көз жеткізуі керек. Осы себепті, C және C++ тілдерінің көпшілігі стандартты емес #pragma once директивасын ұсынады. Бұл директива, бас файлдың басына қосылғанда, файлдың тек бір рет қосылуын қамтамасыз етеді. Objective-C тілі (C тілінің кеңейтілген түрі) #import директивасын енгізді, ол #include сияқты жұмыс істейді, бірақ әрбір файлды бір рет қана қосады, осылайша #include қорғауларының қажеттілігін жояды.