C Препроцесори
Препроцесори са програми, които обработват изходния код преди да започне същинската компилация. Те не са част от процеса на компилиране, но работят отделно, позволявайки на програмистите да променят кода преди компилация.
- Това е първата стъпка, през която преминава изходният код на C, когато се преобразува в изпълним файл.
- Основните типове директиви за препроцесор са Макроси Условна компилация за включване на файлове и други директиви като #undef #pragma и др.
- Основно тези директиви се използват за замяна на даден раздел от C код с друг C код. Например, ако напишем '#define PI 3.14', тогава PI се заменя с 3.14 от препроцесора.
Видове C препроцесори
Всички горепосочени препроцесори могат да бъдат класифицирани в 4 типа:
Макроси
Макроси се използват за дефиниране на константи или създаване на функции, които се заместват от препроцесора преди кодът да бъде компилиран. Двата препроцесора #дефинирай и #undef се използват за създаване и премахване на макроси в C.
#дефинирай символична стойност
#undef жетон
където след предварителна обработка на жетон ще бъде разширен до своя стойност в програмата.
Пример:
C #include // Macro Definition #define LIMIT 5 int main (){ for ( int i = 0 ; i < LIMIT ; i ++ ) { printf ( '%d n ' i ); } return 0 ; }
Изход
0 1 2 3 4
В горната програма, преди да започне компилацията, думата LIMIT се заменя с 5. Думата „ГРАНИЦА“ в дефиницията на макроса се нарича макро шаблон и '5' е макро разширение.
Забележка Няма точка и запетая (;) в края на дефиницията на макроса. Дефинициите на макроси не се нуждаят от точка и запетая в края.
Има и такива Предварително дефинирани макроси в C които са полезни при предоставянето на различни функционалности на нашата програма.
Макрос, дефиниран по-рано, може да бъде недефиниран с помощта на препроцесор #undef. Например в горния код
C #include // Macro Definition #define LIMIT 5 // Undefine macro #undef LIMIT int main (){ for ( int i = 0 ; i < LIMIT ; i ++ ) { printf ( '%d n ' i ); } return 0 ; }
Изход:
./Solution.c: In function 'main': ./Solution.c:13:28: error: 'MAX' undeclared (first use in this function) printf('MAX is: %dn' MAX); ^ ./Solution.c:13:28: note: each undeclared identifier is reported only once for each function it appears inМакроси с аргументи
Можем също да предаваме аргументи на макроси. Тези макроси работят подобно на функциите. например
# дефинирам foo(a b) a + b
#define func(r) r * rНека разберем това с програма:
C#include// macro with parameter #define AREA(l b) (l * b) int main (){ int a = 10 b = 5 ; // Finding area using above macro printf ( '%d' AREA ( a b )); return 0 ; }
ИзходArea of rectangle is: 50Обяснение: В горната програма макросът се дефинира за изчисляване на площта на правоъгълник чрез умножаване на неговата дължина (l) и ширина (б) . Кога ПЛОЩ (a b) се нарича разширява се до (a * b) и резултатът се изчислява и отпечатва.
Моля, направете справка Видове макроси в C за повече примери и типове.
Включване на файл
Включването на файлове ви позволява да включвате външни файлове (библиотеки със заглавни файлове и т.н.) в текущата програма. Това обикновено се прави с помощта на #включи директива, която може да включва както системни, така и дефинирани от потребителя файлове.
Синтаксис
Има два начина за включване на заглавни файлове.
#включи
#включи име на файлThe ' <' и '>' скоби кажете на компилатора да потърси файла в стандартна директория докато двойни кавички ( ' ' ) кажете на компилатора да търси заглавния файл в директорията на изходния файл.
Пример:
C// Includes the standard I/O library #includeint main () { printf ( 'Hello World' ); return 0 ; }
ИзходHello WorldУсловна компилация
Условна компилация ви позволява да включвате или изключвате части от кода в зависимост от определени условия. Това е полезно за създаване на специфичен за платформа код или за отстраняване на грешки. Има следните условни директиви за препроцесор: #if #ifdef #ifndef else #elif и #endif
Синтаксис
Общият синтаксис на условните препроцесори е:
#ако
// някакъв код
#елиф
// още малко код
#друго
// Още малко код
#endifДирективата #endif се използва за затваряне на отварящите директиви #if #ifdef и #ifndef.
Пример
C#include// Defining a macro for PI #define PI 3.14159 int main (){ // Check if PI is defined using #ifdef #ifdef PI printf ( 'PI is defined n ' ); // If PI is not defined check if SQUARE is defined #elif defined(SQUARE) printf ( 'Square is defined n ' ); // If neither PI nor SQUARE is defined trigger an error #else #error 'Neither PI nor SQUARE is defined' #endif // Check if SQUARE is not defined using #ifndef #ifndef SQUARE printf ( 'Square is not defined' ); // If SQUARE is defined print that it is defined #else printf ( 'Square is defined' ); #endif return 0 ; }
ИзходPI is defined Square is not definedОбяснение: Този код използва условни директиви за препроцесор ( #ifdef #elif и #ifndef ), за да проверите дали някои макроси ( ПИ и КВАДРАТ ) са определени. Тъй като PI е дефиниран, програмата отпечатва ' PI е дефиниран ' след това проверява дали SQUARE не е дефиниран и отпечатва ' Квадратът не е дефиниран '.
Други директиви
Освен директивите за първичен препроцесор, C предоставя и други директиви за управление на поведението на компилатора и отстраняване на грешки.
#прагма:
Предоставя конкретни инструкции на компилатора, за да контролира поведението му. Използва се за деактивиране на подравняване на набор от предупреждения и др.
Синтаксис
#прагма директива
Някои от директивите #pragma са разгледани по-долу:
- #pragma стартиране: Тези директиви ни помагат да уточним функциите, които са необходими за изпълнение преди стартиране на програмата (преди управлението да премине към main()).
- #pragma изход : Тези директиви ни помагат да посочим функциите, които са необходими за изпълнение точно преди изхода на програмата (точно преди контролата да се върне от main()).
Пример
C#includevoid func1 (); void func2 (); // specifying funct1 to execute at start #pragma startup func1 // specifying funct2 to execute before end #pragma exit func2 void func1 () { printf ( 'Inside func1() n ' ); } void func2 () { printf ( 'Inside func2() n ' ); } int main (){ void func1 (); void func2 (); printf ( 'Inside main() n ' ); return 0 ; }
ИзходInside main()Горният код ще произведе изхода, както е даден по-горе, когато се изпълнява на GCC компилатори, докато очакваният изход е:
Очакван резултат
Inside func1() Inside main() Inside func2()Това се случва, защото GCC не поддържа #pragma стартиране или излизане. Въпреки това можете да използвате кода по-долу за очаквания изход на компилаторите на GCC.
C#includevoid func1 (); void func2 (); void __attribute__ (( constructor )) func1 (); void __attribute__ (( destructor )) func2 (); void func1 () { printf ( 'Inside func1() n ' ); } void func2 () { printf ( 'Inside func2() n ' ); } int main () { printf ( 'Inside main() n ' ); return 0 ; }
ИзходInside func1() Inside main() Inside func2()В горната програма сме използвали някои специфичен синтаксис така че една от функциите да се изпълнява преди основната функция, а другата да се изпълнява след основната функция.
Създаване на тест