2009-07-16 3 views
93

Как встроенная функция отличается от макроса препроцессора?Встроенные функции против макросов препроцессора

+3

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

+0

Ответы на http://stackoverflow.com/questions/132738/why-should-i-ever-use-inline-code содержит некоторую информацию, связанную с вашим вопросом. –

ответ

108

Макросы препроцессора - это просто шаблоны замещения, применяемые к вашему коду. Их можно использовать практически в любом месте вашего кода, потому что они заменяются их расширениями перед началом компиляции.

Внутренние функции - это фактические функции, чье тело непосредственно впрыскивается в их сайт вызова. Они могут использоваться только там, где подходит вызов функции.

Теперь, насколько использование макросов vs. встроенных функций в функции, как контекст, иметь в виду, что:

  • Макросы не типобезопасен, и может быть расширен, независимо от того, являются ли они синтаксически правильно - на этапе компиляции будут сообщаться ошибки, возникающие из-за проблем с макрообъемностью.
  • Макросы могут использоваться в контексте, где вы не ожидаете, в результате чего возникают проблемы
  • Макросы более гибкие, поскольку они могут расширять другие макросы, тогда как встроенные функции необязательно делают это.
  • Макросы могут вызывать побочные эффекты из-за их расширения, поскольку входные выражения копируются везде, где они отображаются в шаблоне.
  • Не всегда встроенная функция Inline - некоторые компиляторы делают это только в сборках релизов или когда они специально настроены для этого. Кроме того, в некоторых случаях встраивание может быть невозможно.
  • Встроенные функции могут предоставить область переменных (в частности, статические), макросы препроцессора могут делать это только в блоках кода {...}, а статические переменные не будут вести себя точно так же.
+26

Не всегда гарантируется встроенная функция: поскольку компилятор не будет встроен, если это приведет к созданию более медленного кода и т. Д. Компилятор делает много анализа, который Инженер не может и делает правильно. –

+10

Я считаю, что рекурсивные функции - еще один пример, когда большинство компиляторов игнорируют inlining. – LBushkin

+0

Существуют ли какие-либо важные различия в C по сравнению с C++ в этом случае? – rzetterberg

11

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

Here - несколько других менее очевидных точек, обозначенных.

1

Встроенная функция ведет себя синтаксически, как обычная функция, обеспечивая безопасность типов и область действия для локальных переменных функций и доступ к членам класса, если это метод. Также при вызове встроенных методов вы должны придерживаться частных/защищенных ограничений.

2

Встроенная функция будет поддерживать семантику значений, тогда как макрос препроцессора просто копирует синтаксис. Вы можете получить очень тонкие ошибки с помощью макроса препроцессора, если вы используете этот аргумент несколько раз - например, если аргумент содержит мутацию типа «i ++», которая имеет два раза, это довольно неожиданно. Эта встроенная функция не будет иметь этой проблемы.

8

Макросы игнорируют пространства имен. И это делает их злыми.

63

Во-первых, макросы препроцессора - это всего лишь «скопировать пасту» в код перед компиляцией.Так что нет типа проверки, и некоторые побочных эффектов могут появиться

Например, если вы хотите сравнить 2 значения:

#define max(a,b) ((a<b)?b:a) 

сторона появляются эффекты, если вы используете max(a++,b++), например (a или b будет увеличиваться дважды). Вместо этого следует использовать (например)

inline int max(int a, int b) { return ((a<b)?b:a); } 
+0

Просто добавьте к вашему примеру, что помимо побочного эффекта макрос может также ввести дополнительную рабочую нагрузку, рассмотрим 'max (fibonacci (100), factorial (10000))', более крупный будет вычисляться дважды :( – watashiSHUN

0

В GCC (я не уверен, о других), объявив функцию инлайн, это всего лишь намек на компилятор. В конце дня все еще зависит от компилятора, чтобы решить, включает ли он тело функции всякий раз, когда он вызывается.

Разница между встроенными функциями и макросами препроцессора относительно велика. Макросы препроцессора - это просто замена текста в конце дня. Вы отказываетесь от способности компилятора выполнять проверку проверки типов на аргументы и тип возвращаемого значения. Оценка аргументов сильно отличается (если выражения, которые вы передаете в функции, имеют побочные эффекты, вы будете очень весело отлаживать время). Существуют тонкие различия в том, где можно использовать функции и макросы. Например, если у меня было:

#define MACRO_FUNC(X) ... 

Где MACRO_FUNC, очевидно, определяет тело функции. Особое внимание должно быть принято, так что работает правильно во всех случаях функция может быть использована, например, плохо написана MACRO_FUNC вызовет ошибку в

if(MACRO_FUNC(y)) { 
...body 
} 

нормальная функция может быть использована без проблем там.

9

Чтобы добавить еще одно отличие от уже предоставленных: вы не можете пройти через #define в отладчике, но вы можете выполнить встроенную функцию.

0

С точки зрения кодирования встроенная функция подобна функции. Таким образом, различия между встроенной функцией и макросом совпадают с различиями между функцией и макросом.

С точки зрения компиляции встроенная функция похожа на макрос. Он вводится непосредственно в код, не вызываемый.

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

3

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

  • Встроенные функции соответствуют всем протоколам типа безопасности, действующим на нормальных функциях.
  • Встроенные функции задаются с использованием того же синтаксиса, что и любая другая функция, за исключением того, что они включают ключевое слово inline в объявлении функции.
  • Выражения, переданные как аргументы встроенным функциям, оцениваются один раз.
  • В некоторых случаях выражения, переданные в качестве аргументов для макросов, могут быть оценены более одного раза. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx

  • макросы расширяются за время предварительной компиляции, вы не можете использовать их для отладки, но вы можете использовать встроенные функции.

-- good article: http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

;

+0

Спасибо, сэр за ваш ответ. – Subodh

0

встроенные функции будут вести себя как вызов функции, если в нем есть итеративный или рекурсивный оператор, чтобы предотвратить повторное выполнение инструкций. Это очень полезно для сохранения общей памяти вашей программы.

функция
12

инлайн расширяется компилятором, где, как макросы развернутом препроцессора, который просто текстуальное substitution.Hence

  • Там нет проверки типа во время вызова макроса во время проверки типа делаются во время вызов функции.

  • Нежелательные результаты и неэффективность могут возникать во время расширения макросов из-за переоценки аргументов и порядка операций. Например

    #define MAX(a,b) ((a)>(b) ? (a) : (b)) 
    int i = 5, j = MAX(i++, 0); 
    

    приведет

    int i = 5, j = ((i++)>(0) ? (i++) : (0)); 
    
  • макросоци- аргументы не оценены до макроподстановкам

    #define MUL(a, b) a*b 
    int main() 
    { 
        // The macro is expended as 2 + 3 * 3 + 5, not as 5*8 
        printf("%d", MUL(2+3, 3+5)); 
    return 0; 
    } 
    // Output: 16` 
    
  • Возвращение ключевого слова не могут быть использованы в макросах возвращать значения, как в случай функций.

  • Встраиваемые функции могут быть перегружены

  • Маркеры, передаваемые макросы могут быть объединены при помощи оператора ##, называемый оператором Токен-наклеивая.

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

Смежные вопросы