Вычисление аргументов макросов в C

#c #macros #inline

#c #макросы #встроенный

Вопрос:

Я не понимаю, в чем причина того, что макросы не оценивают свой аргумент только один раз (например, встроенные функции), но каждый раз, когда он используется в коде.

Например:

(пример взят отсюда: https://docs.microsoft.com/en-us/cpp/cpp/inline-functions-cpp?view=msvc-170 )

В этом коде есть макрос:

 
// inline_functions_macro.c
#include <stdio.h>
#include <conio.h>

#define toupper(a) ((a) >= 'a' amp;amp; ((a) <= 'z') ? ((a)-('a'-'A')):(a))

int main() {
   char ch;
   printf_s("Enter a character: ");
   ch = toupper( getc(stdin) );
   printf_s( "%c", ch );
}
//  Sample Input:  xyz
// Sample Output:  Z


 

По сравнению с этим кодом с эквивалентной встроенной функцией:

 // inline_functions_inline.cpp
#include <stdio.h>
#include <conio.h>

inline char toupper( char a ) {
   return ((a >= 'a' amp;amp; a <= 'z') ? a-('a'-'A') : a );
}

int main() {
   printf_s("Enter a character: ");
   char ch = toupper( getc(stdin) );
   printf_s( "%c", ch );
}

 

Комментарии:

1. Макросы представляют собой текстовые замены. Они не являются функциями.

2. Макросы не являются функциями. Это замена текста в препроцессоре, вот и все. Ни больше, ни меньше. Похоже, что ваш исходный код буквально содержит замененный текст, выполненный препроцессором, поэтому компилятор жалуется на использование каждого макроса, а не самого макроса.

3. Важно понимать, что макросы расширяются перед компиляцией, в том, что обычно называют «фазой предварительной обработки».

4. Попробуйте развернуть макрос со следующими аргументами: «hello» и 3.1415269. Это должно показать вам, почему функции предпочтительнее макросов.

Ответ №1:

Макросы не очень умны. Они просто выполняют подстановку текста перед началом компиляции.

Код:

 #define toupper(a) ((a) >= 'a' amp;amp; ((a) <= 'z') ? ((a)-('a'-'A')):(a))

int main() {
   char ch = toupper( getc(stdin) );
}
 

Инструктирует препроцессор изменить этот код и вместо этого передать его компилятору:

 int main() {
   char ch = ((getc(stdin)) >= 'a' amp;amp; ((getc(stdin)) <= 'z') ? ((getc(stdin))-('a'-'A')):(getc(stdin)));
}
 

Вы можете заметить, что toupper это было заменено определенным выражением, в то время как каждое вхождение a заменяется любым текстом, который был передан в качестве параметра макроса. Это не значение или выражение — это просто текст.

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