Рубрики

Интересные факты о макросах и препроцессорах в Си

В программе на Си все строки, начинающиеся с # , обрабатываются препроцессором, который является специальной программой, вызываемой компилятором. Проще говоря, препроцессор берет программу на C и создает другую программу на C без знака # .

Ниже приведены некоторые интересные факты о препроцессорах в C.
1) Когда мы используем директиву include , содержимое включенного заголовочного файла (после предварительной обработки) копируется в текущий файл.
Угловые скобки < и > указывают препроцессору искать в стандартной папке, где хранятся все заголовочные файлы. Двойные кавычки « и » инструктируют препроцессор искать текущую папку (текущий каталог).
2) Когда мы используем define для константы, препроцессор создает программу на C, где выполняется поиск определенной константы и соответствующие токены заменяются данным выражением. Например, в следующей программе max определяется как 100.

#include<stdio.h>
#define max 100

int main()

{

    printf("max is %d", max);

    return 0;

}

Выход:

max is 100

3) Макросы могут принимать функции как аргументы, аргументы не проверяются на тип данных. Например, следующий макрос INCREMENT (x) может использоваться для x любого типа данных.

#include <stdio.h>
#define INCREMENT(x) ++x

int main()

{

    char *ptr = "GeeksQuiz";

    int x = 10;

    printf("%s  ", INCREMENT(ptr));

    printf("%d", INCREMENT(x));

    return 0;

}

Выход:

eeksQuiz  11

4) Аргументы макроса не оцениваются до раскрытия макроса. Например, рассмотрим следующую программу

#include <stdio.h>
#define MULTIPLY(a, b) a*b

int main()

{

    // Макрос расходуется как 2 + 3 * 3 + 5, а не как 5 * 8

    printf("%d", MULTIPLY(2+3, 3+5));

    return 0;

}
// Вывод: 16

Выход:

16

Предыдущая проблема может быть решена с помощью следующей программы

#include <stdio.h>
// здесь вместо записи a * a пишем (a) * (b)
#define MULTIPLY(a, b) (a)*(b)

int main()

{

    // Макрос расходуется как (2 + 3) * (3 + 5), как 5 * 8

    printf("%d", MULTIPLY(2+3, 3+5));

    return 0;

}
// Этот код предоставлен Santanu

Выход:

40

5) Токены, передаваемые макросам, могут быть объединены с помощью оператора ##, называемого оператором вставки токенов.

#include <stdio.h>
#define merge(a, b) a##b

int main()

{

    printf("%d ", merge(12, 34));

}

Выход:

1234

6) Токен, переданный макросу, может быть преобразован в строковый литерал с помощью символа # перед ним.

#include <stdio.h>
#define get(a) #a

int main()

{

    // GeeksQuiz изменяется на "GeeksQuiz"

    printf("%s", get(GeeksQuiz));

}

Выход:

GeeksQuiz

7) Макросы могут быть записаны в несколько строк с помощью «/». Последняя строка не должна иметь «/».

#include <stdio.h>
#define PRINT(i, limit) while (i < limit) \

                        { \

                            printf("GeeksQuiz "); \

                            i++; \

                        }

int main()

{

    int i = 0;

    PRINT(i, 3);

    return 0;

}

Выход:

GeeksQuiz GeeksQuiz GeeksQuiz

8) Следует избегать макросов с аргументами, поскольку они иногда вызывают проблемы. И встроенные функции должны быть предпочтительнее, так как в встроенных функциях есть оценка параметров проверки типа. Начиная с C99 , встроенные функции также поддерживаются языком Си.
Например, рассмотрим следующую программу. С первого взгляда вывод кажется равным 1, но он выдает 36 как вывод.

#include <stdio.h>

  
#define square(x) x*x

int main()

{

    // Развернуто как 36/6 * 6

    int x = 36/square(6); 

    printf("%d", x);

    return 0;

}

Выход:

36

Если мы используем встроенные функции, мы получаем ожидаемый результат. Кроме того, программу, приведенную в пункте 4 выше, можно исправить с помощью встроенных функций.

#include <stdio.h>

  

static inline int square(int x) { return x*x; }

int main()

{

int x = 36/square(6);

printf("%d", x);

return 0;

}

Выход:

1

9) Препроцессоры также поддерживают директивы if-else, которые обычно используются для условной компиляции.

int main()

{
#if VERBOSE >= 2

  printf("Trace Message");

#endif
}

Выход:

No Output

10) Заголовочный файл может быть включен более одного раза прямо или косвенно, что приводит к проблемам с повторной декларацией одних и тех же переменных / функций. Чтобы избежать этой проблемы, директивы как определено, IfDef и IfNDef используются.
11) Существует несколько стандартных макросов, которые можно использовать для печати файла программы (__FILE__), даты компиляции (__DATE__), времени компиляции (__TIME__) и номера строки в коде C (__LINE__)

#include <stdio.h>

  

int main()

{

   printf("Current File :%s\n", __FILE__ );

   printf("Current Date :%s\n", __DATE__ );

   printf("Current Time :%s\n", __TIME__ );

   printf("Line Number :%d\n", __LINE__ );

   return 0;

}

Выход:

Current File :/usr/share/IDE_PROGRAMS/C/other/081c548d50135ed88cfa0296159b05ca/081c548d50135ed88cfa0296159b05ca.c
Current Date :Sep  4 2019
Current Time :10:17:43
Line Number :9

12) Мы можем удалить уже определенные макросы, используя: #undef MACRO_NAME

#include <stdio.h>
#define LIMIT 100

int main()

{

   printf("%d",LIMIT);

   // удаляем определенный макрос LIMIT

   #undef LIMIT

   // Следующая строка вызывает ошибку, так как LIMIT не определен

   printf("%d",LIMIT);

   return 0;

}
// Этот код предоставлен Santanu

Следующая программа выполняется правильно, так как мы объявили LIMIT как целочисленную переменную после удаления ранее определенного макроса LIMIT

#include <stdio.h>
#define LIMIT 1000

int main()

{

   printf("%d",LIMIT);

   // удаляем определенный макрос LIMIT

   #undef LIMIT

   // Объявляем LIMIT как целое число снова

   int LIMIT=1001;

   printf("\n%d",LIMIT);

   return 0;

}

Выход:

1000
1001

Еще один интересный факт об использовании макросов ( #undef )

#include <stdio.h>
// прототип функции div

float div(float, float);

#define div(x, y) x/y

  

int main()

{
// использование макроса div
// Примечание:% 0.2f для получения двух десятичных значений после точки

printf("%0.2f",div(10.0,5.0));

// удаляем определенный макрос div
#undef div
// функция div вызывается при удалении определения макроса

printf("\n%0.2f",div(10.0,5.0));

return 0;

}

  
// определение функции div

float div(float x, float y){

return y/x;

}
// Этот код предоставлен Santanu

Выход:

2.00
0.50

Вы можете пройти тест на макросы и препроцессоры в C

Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.

Рекомендуемые посты:

Интересные факты о макросах и препроцессорах в Си

0.00 (0%) 0 votes