Кіріспе
Бірнеше бағдарламалау тілдері үшін макро-алдын ала өңдеуші
C препроцессоры – C, Objective-C, C++ және түрлі Fortran тілдері сияқты бірнеше компьютерлік бағдарламалау тілдері үшін макро-алдын ала өңдеуші. Препроцессор бас файлдарды қосу, макростарды кеңейту, шартты компиляция және жолдарды басқару мүмкіндіктерін ұсынады. Препроцессор директиваларының тілі C тілінің грамматикасымен тығыз байланысты емес, сондықтан кейде басқа мәтіндік файлдарды өңдеу үшін де қолданылады.
Тарих
Алдын ала процессор 1973 жыл шамасында Алан Снайдердің ықпалымен және BCPL мен PL/I тілдеріндегі файлдарды қосу мүмкіндігінің пайдалылығын мойындау үшін C тіліне енгізілді. Оның алғашқы нұсқасы #include және #define директиваларын пайдаланып, файлдарды қосу және параметрсіз макростар үшін қарапайым жолдарды алмастыру мүмкіндіктерін ұсынды. Біраз уақыттан кейін Майк Леск, содан кейін Джон Райзер оны кеңейтіп, аргументтері бар макростар мен шартты компиляцияны қосты. C алдын ала процессоры 1959 жылы Дуглас Иствуд пен Дуглас Макилрой бастаған Bell Labs мекемесіндегі макро тілдерінің ұзақ дәстүрінің бір бөлігі болды.
Фазалары
Алдын ала өңдеу C стандартында белгіленген аударманың алғашқы төрт (сегіз) кезеңімен анықталады. Триграфтарды алмастыру: Алдын ала өңдеуші триграф тізбектерін олар көрсететін символдармен алмастырады. C++17 қадамдарын орындау бойынша C23 стандартында бұл кезең жойылады. Жолдарды біріктіру: Эскейптелген жаңа жол тізбектерімен жалғасатын физикалық бастапқы жолдар логикалық жолдарды құру үшін біріктіріледі. Токендеу: Алдын ала өңдеуші нәтижені алдын ала өңдеу токендері мен бос орындарға бөледі. Ол сондай-ақ түсініктемелерді бос орынмен алмастырады. Макростарды кеңейту және директиваларды өңдеу: Файлдарды қосу және шартты компиляцияны қамтитын, алдын ала өңдеу директивалары орындалады. Алдын ала өңдеуші бір мезгілде макростарды кеңейтеді және 1999 жылғы C стандартының нұсқасынан бастап Pragma операторларын өңдейді.
Бинарлық ресурсты қосу
C23 бинарлық ресурстарды қосу үшін #embed директивасын енгізеді. Бұл екілік файлдарды (мысалы, суреттерді) бағдарламаға C бастапқы файлдары (XBM сияқты) ретінде жарамсыз болса, xxd i сияқты сыртқы құралдармен өңдеуді қажет етпей және MSVC-де ұзындығы шектеулі жолдарды пайдаланбай қосуға мүмкіндік береді. xxd i сияқты, директива көрсетілген ресурстың деректеріне сәйкес келетін сандардың үтірмен бөлінген тізімімен алмастырылады. Нақтырақ айтқанда, егер #embed директивасын пайдаланып массив инициализацияланса, нәтиже ресурс fread арқылы массивқа жазылғандай болады (егер параметр embed элементінің енін CHAR BIT-тен өзгешеге өзгерте қоймаса). Ыңғайлылығынан басқа, #embed компиляторлар үшін де оңай, өйткені оларға директиваны толық түріне кеңейтуді өткізіп жіберуге рұқсат етіледі. Қосылатын файл #include сияқты, яғни бұрыш жақшалардың немесе тырнақшалардың арасында көрсетілуі мүмкін. Директива файл атауынан кейін берілетін параметрлерді қабылдауға мүмкіндік береді, олар оның әрекетін бейімдеуге арналған. C стандарты келесі параметрлерді анықтайды, ал жүзеге асырулар өздерінің параметрлерін анықтай алады. limit параметрі қосылған деректің енін шектеу үшін қолданылады. Ол көбінесе urandom сияқты "шексіз" файлдармен пайдалануға арналған. prefix және suffix параметрлері бағдарламашыға кіріктірілген деректерге префикс пен суффикс қоюға мүмкіндік береді, бұл кіріктірілген ресурс бос болмаса ғана қолданылады. Соңында, if empty параметрі ресурс бос болса, директиваның барлығын алмастырады (бұл файл бос болса немесе 0 лимиті көрсетілген болса болады). Барлық стандартты параметрлер C23-тегі стандартты атрибуттар сияқты қос астын сызықтармен қоршалуы мүмкін, мысалы, prefix параметрі prefix параметрімен алмастырылуы мүмкін. Жүзеге асыруға қатысты анықталған параметрлер атрибут синтаксисіне ұқсас пішінде қолданылады (мысалы, vendor::attr), бірақ тік жақшаларсыз. Барлық стандартты параметрлерге аргумент беру талап етілсе де (мысалы, limit ені қажет), бұл әдетте міндетті емес, тіпті аргумент қажет болмаса, жақшалар жиынтығын да жоюға болады, бұл кейбір жүзеге асыруға қатысты анықталған параметрлер үшін мүмкін.
Қолданылу
Барлық C, C++ және Objective C іске асырылымдары алдын ала өңдеушімен жабдықталған, себебі алдын ала өңдеу осы тілдер үшін міндетті қадам болып табылады, ал оның жұмысы ISO C стандарты сияқты осы тілдерге арналған ресми стандарттармен сипатталған. Іске асырылымдар өздерінің қосымша мүмкіндіктерін және стандарттан ауытқуларын ұсынуы мүмкін, сондай-ақ жазбаша стандарттарға сәйкес келу дәрежесі де әртүрлі болуы мүмкін. Олардың нақты жұмысы шақырылған кезде берілген командалық қатардағы параметрлерге байланысты өзгеруі мүмкін. Мысалы, GNU C алдын ала өңдеушісі белгілі бір параметрлерді қосу арқылы стандарттарға сәйкес жұмыс істеуі мүмкін.
Компиляторға тән алдын ала өңдеуші ерекшеліктері
#pragma директивасы – компиляторға арналған ерекше директива, оны компилятор өндірушілер өз мақсаттары үшін пайдалана алады. Мысалы, #pragma жиі белгілі бір қате хабарламаларын жоюға, үйінді және стекті түзетуді басқаруға және тағы да басқаларға қолданылады. OpenMP параллелдеу кітапханасын қолдайтын компилятор #pragma omp parallel for арқылы for циклін автоматты түрде параллелдей алады. C99 жылжымалы нүктелерді іске асыруды басқару үшін #pragma STDC түрінде бірнеше стандартты #pragma директиваларын енгізді. Сонымен қатар, макросқа ұқсас формасы да қосылды. Көптеген іске асырулар триграфтарды қолдамайды немесе оларды әдепкі бойынша алмастырмайды. Көптеген іске асырулар (мысалы, GNU, Intel, Microsoft және IBM C компиляторлары) шығысқа ескерту хабарламасын шығару үшін стандартты емес директиваны ұсынады, бірақ компиляция процесін тоқтатпайды (C23 және C++23 осы мақсат үшін стандартқа қосылады). Типик қолданылуы – ескі кодты пайдалану туралы ескерту, ол қазір қолданылмайды және тек үйлесімділік үшін ғана қосылған; мысалы: // GNU, Intel және IBM #warning "Ескірген ABC-ді пайдаланбаңыз. Оның орнына XYZ-ді пайдаланыңыз." // Microsoft #pragma message("Ескірген ABC-ді пайдаланбаңыз. Оның орнына XYZ-ді пайдаланыңыз.") Кейбір Unix препроцессорлары дәстүрлі түрде бағдарламалауда қолданылатын асерциялардан өзгеше "асерцияларды" ұсынды. GCC бірдей аттағы заголовоктарды тізбектеу үшін #include next мүмкіндігін қамтамасыз етеді.
#warning "Do not use ABC, which is deprecated. Use XYZ instead. "// Microsoft
#pragma message("Do not use ABC, which is deprecated. Use XYZ instead.") Some Unix preprocessors traditionally provided "assertions," which have little similarity to assertions used in programming. GCC provides #include next for chaining headers of the same name.
Тілге тән алдын ала өңдеуші ерекшеліктері
Кейбір тілдердің сипаттамаларына сәйкес C препроцессорына қосылған, сондай-ақ аталған тілдерге ғана тән препроцессорлық директивалар бар. Objective-C препроцессорларында #import директивасы бар, ол #include сияқты жұмыс істейді, бірақ файлды бір рет қана қосады. C тілінде осыған ұқсас қызмет атқаратын, кең таралған өндірушінің прагмасы #pragma once болып табылады. C++ тілі C++20 нұсқасынан бастап модульдер үшін import және module директиваларын қолдайды. Бұл директивалар # белгісімен басталмайды, олар import және module сөздерімен басталады, алдынан export сөзі де қосылуы мүмкін.
Басқа қолданыстар
C препроцессоры онымен бірге келген компилятордан бөлек шақырылуы мүмкін болғандықтан, оны әртүрлі тілдерде жеке пайдалануға болады. Көрінетін мысалдардың бірі – қазір қолданыстан шыққан imake жүйесі және Fortran-ды алдын ала өңдеу. Дегенмен, оны жалпы мақсаттағы препроцессор ретінде пайдалану мүмкіндігі шектеулі: кіріс тілі C тіліне жеткілікті ұқсас болуы керек. Intel, ifort компиляторымен қолдануға арналған Fortran препроцессорын, fpp ұсынады, ол ұқсас мүмкіндіктерге ие. CPP көптеген ассемблер тілдерімен және Algol сияқты тілдермен де жақсы жұмыс істейді. Бұл үшін тілдің синтаксисі CPP синтаксисімен қақтығыспауы керек, яғни жолдар # таңбасымен басталмауы керек, ал cpp мәтіндік тізбек ретінде қабылдап елемейтін қос тырнақшалардың синтаксистік мағынасы болмауы керек. «Традициялық режим» (ISO C препроцессоры сияқты жұмыс істеу) көбінесе көбірек мүмкіндіктер береді және мұндай қолдану үшін жақсырақ жарасады. C препроцессоры толыққанды Тьюринг машинасы емес, бірақ оған өте жақын: рекурсивті есептеулерді анықтауға болады, бірақ рекурсияның орындалу мөлшеріне белгілі бір шектеу қойылады. Алайда, C препроцессоры жалпы мақсаттағы бағдарламалау тілі ретінде жасалмаған және осы салада тиімді жұмыс істемейді. C препроцессоры рекурсивті макростар, цитатаға сәйкес таңдап кеңейту және шартты операторлардағы тізбектерді бағалау сияқты басқа препроцессорлардың мүмкіндіктеріне ие болмағандықтан, m4 сияқты күшті макропроцессормен салыстырғанда өте шектеулі.