Рубрики

Встроенные функции в C ++

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

Когда программа выполняет инструкцию вызова функции, ЦПУ сохраняет адрес памяти инструкции, следующей за вызовом функции, копирует аргументы функции в стек и, наконец, передает управление указанной функции. Затем ЦПУ выполняет код функции, сохраняет возвращаемое значение функции в заранее определенной ячейке памяти / регистре и возвращает управление вызывающей функции. Это может стать издержкой, если время выполнения функции меньше, чем время переключения с вызывающей функции на вызываемую функцию (вызываемый). Для функций, которые являются большими и / или выполняют сложные задачи, накладные расходы на вызов функции обычно незначительны по сравнению с количеством времени, которое требуется функции для запуска. Однако для небольших, часто используемых функций время, необходимое для вызова функции, часто намного больше, чем время, необходимое для фактического выполнения кода функции. Эти издержки возникают для небольших функций, потому что время выполнения маленькой функции меньше, чем время переключения.

C ++ предоставляет встроенные функции для уменьшения накладных расходов на вызовы функций. Встроенная функция — это функция, которая раскрывается в строке при ее вызове. Когда вызывается встроенная функция, весь код встроенной функции вставляется или заменяется в точке вызова встроенной функции. Эта замена выполняется компилятором C ++ во время компиляции. Встроенная функция может повысить эффективность, если она мала.
Синтаксис для определения встроенной функции:

inline return-type function-name(parameters)
{
    // function code
}  

Помните, что встраивание — это только запрос к компилятору, а не команда. Компилятор может игнорировать запрос на встраивание. Компилятор может не выполнять встраивание в таких обстоятельствах, как:
1) Если функция содержит цикл. (пока, пока-пока)
2) Если функция содержит статические переменные.
3) Если функция рекурсивная.
4) Если тип возвращаемого значения функции отличается от void, и оператор возврата не существует в теле функции.
5) Если функция содержит оператор switch или goto.

Встроенные функции обеспечивают следующие преимущества:
1) Затраты на вызов функции не происходят.
2) Это также экономит накладные расходы на переменные push / pop в стеке при вызове функции.
3) Это также экономит накладные расходы на обратный вызов из функции.
4) Когда вы встраиваете функцию, вы можете разрешить компилятору выполнять контекстно-зависимую оптимизацию тела функции. Такая оптимизация невозможна для обычных вызовов функций. Другие оптимизации могут быть получены путем рассмотрения потоков вызывающего контекста и вызываемого контекста.
5) Встроенная функция может быть полезна (если она мала) для встроенных систем, поскольку встроенная функция может дать меньше кода, чем преамбула вызова функции и возврат.

Недостатки встроенной функции:
1) Добавленные переменные из встроенной функции потребляют дополнительные регистры, после встроенной функции, если число переменных, которые собираются использовать регистр, увеличивается, чем они могут создать издержки при использовании ресурсов переменных регистра. Это означает, что когда подставляется тело встроенной функции в точке вызова функции, также вставляется общее количество переменных, используемых функцией. Таким образом, число регистров, которые будут использоваться для переменных, также будет увеличено. Так что если после встраивания функции число номеров переменных резко возрастет, то это наверняка вызовет дополнительные затраты на использование регистра.

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

3) Слишком большое встраивание может также снизить частоту обращений к кешу инструкций, тем самым уменьшая скорость выборки инструкций от скорости кэш-памяти до основной памяти.

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

5) Встроенные функции могут быть бесполезны для многих встроенных систем. Потому что во встроенных системах размер кода важнее скорости.

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

Следующая программа демонстрирует использование встроенной функции.

#include <iostream>

using namespace std;

inline int cube(int s)

{

    return s*s*s;

}

int main()

{

    cout << "The cube of 3 is: " << cube(3) << "\n";

    return 0;

} // Вывод: куб 3 равен: 27

Встроенная функция и классы:
Также возможно определить встроенную функцию внутри класса. Фактически все функции, определенные внутри класса, неявно встроены. Таким образом, все ограничения встроенных функций также применяются здесь. Если вам нужно явно объявить встроенную функцию в классе, просто объявите функцию внутри класса и определите ее вне класса, используя ключевое слово inline.
Например:

class S

{

public:

    inline int square(int s) // избыточное использование inline

    {

        // эта функция автоматически встроена

        // тело функции

    }

};

Вышеуказанный стиль считается плохим стилем программирования. Лучший стиль программирования — просто написать прототип функции внутри класса и указать его в качестве встроенного в определении функции.
Например:

class S

{

public:

    int square(int s); // объявляем функцию

};

  

inline int S::square(int s) // использовать встроенный префикс

{

  
}

Следующая программа демонстрирует эту концепцию:

#include <iostream>

using namespace std;

class operation

{

    int a,b,add,sub,mul;

    float div;

public:

    void get();

    void sum();

    void difference();

    void product();

    void division();

};

inline void operation :: get()

{

    cout << "Enter first value:";

    cin >> a;

    cout << "Enter second value:";

    cin >> b;

}

  

inline void operation :: sum()

{

    add = a+b;

    cout << "Addition of two numbers: " << a+b << "\n";

}

  

inline void operation :: difference()

{

    sub = a-b;

    cout << "Difference of two numbers: " << a-b << "\n";

}

  

inline void operation :: product()

{

    mul = a*b;

    cout << "Product of two numbers: " << a*b << "\n";

}

  

inline void operation ::division()

{

    div=a/b;

    cout<<"Division of two numbers: "<<a/b<<"\n" ;

}

  

int main()

{

    cout << "Program using inline function\n";

    operation s;

    s.get();

    s.sum();

    s.difference();

    s.product();

    s.division();

    return 0;

}

Выход:

Enter first value: 45
Enter second value: 15
Addition of two numbers: 60
Difference of two numbers: 30
Product of two numbers: 675
Division of two numbers: 3 

Что не так с макросом?
Читатели, знакомые с языком C, знают, что язык C использует макрос. Препроцессор заменяет все вызовы макросов непосредственно в коде макроса. Рекомендуется всегда использовать встроенную функцию вместо макроса. По словам доктора Бьярне Страуструпа, создателя C ++, макросы почти никогда не нужны в C ++ и подвержены ошибкам. Есть некоторые проблемы с использованием макросов в C ++. Макрос не может получить доступ к закрытым членам класса. Макрос выглядит как вызов функции, но на самом деле это не так.
Пример:

#include <iostream>

using namespace std;

class S

{

    int m;

public:

#define MAC(S::m)    // error
};

Компилятор C ++ проверяет типы аргументов встроенных функций, и необходимые преобразования выполняются правильно. Макрос препроцессора не способен на это. Еще одна вещь состоит в том, что макросы управляются препроцессором, а встроенные функции управляются компилятором C ++.

Помните: верно, что все функции, определенные внутри класса, неявно встроены, и компилятор C ++ будет выполнять встроенный вызов этих функций, но компилятор C ++ не может выполнять вставку, если функция виртуальная. Причина в том, что вызов виртуальной функции разрешается во время выполнения, а не во время компиляции. Виртуальные средства ждут до времени выполнения и встроенные средства во время компиляции, если компилятор не знает, какая функция будет вызвана, как он может выполнять встраивание?

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

inline void show()

{

    cout << "value of S = " << S << endl;

}

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

В зависимости от того, какой компилятор вы используете, он может показывать вам предупреждение, если функция не развернута в строке. Языки программирования, такие как Java & C #, не поддерживают встроенные функции.
Но в Java компилятор может выполнять встраивание при вызове маленького метода final, потому что методы final не могут быть переопределены подклассами, и вызов метода final разрешается во время компиляции. В C # JIT-компилятор также может оптимизировать код, вставляя небольшие вызовы функций (например, заменяя тело небольшой функции, когда она вызывается в цикле).

Последнее, что нужно иметь в виду, что встроенные функции — это ценная особенность C ++. Надлежащее использование встроенной функции может обеспечить повышение производительности, но если встроенные функции используются произвольно, они не могут обеспечить лучший результат. Другими словами, не ожидайте лучшей производительности программы. Не делайте каждую функцию встроенной. Лучше, чтобы встроенные функции были как можно меньше.

Ссылки:
1) Эффективный C ++, Скотт Мейерс
2) http://www.parashift.com/c++-faq/inline-and-perf.html
3) http://www.cplusplus.com/forum/articles/20600/
4) Мышление в C ++, том 1, Брюс Экель .
5) C ++ полная ссылка, Герберт Шильдт

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

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

Встроенные функции в C ++

0.00 (0%) 0 votes