Какова / есть цель (и) inline? - PullRequest
       18

Какова / есть цель (и) inline?

15 голосов
/ 05 сентября 2010

У меня было обсуждение с Йоханнесом Шаубом относительно ключевого слова inline.Код там был такой:

namespace ... {
    static void someFunction() {
        MYCLASS::GetInstance()->someFunction();
    }
};

Он заявил, что:

Использование этой функции в качестве встроенной функции может сохранить размер кода в исполняемом файле

Но согласно моим выводам здесь и здесь в этом не будет необходимости, поскольку:

  • [Inline] происходит только в том случае, если стоимость компилятораАнализ выгод / показывает, что это выгодно
  • Основные компиляторы C ++, такие как Microsoft Visual C ++ и GCC, поддерживают опцию, которая позволяет компиляторам автоматически включать любые подходящие функции, даже те, которые не помечены как встроенные функции.

Однако Йоханнес утверждает, что есть и другие преимущества его явного указания.К сожалению я их не понимаю.Например, он заявил, что И «inline» позволяет вам определять функцию несколько раз в программе. , что мне трудно понять (и найти ссылки).

Итак,

  1. Является ли inline рекомендацией для компилятора?
  2. Должно ли это быть явно указано, когда у вас небольшая функция (я полагаю, 1-4 инструкции?)
  3. Какие еще преимущества есть при написании inline?
  4. нужно ли указывать inline, чтобы уменьшить размер исполняемого файла, даже если компилятор (согласно википедии [я знаю, плохоссылка]) должен сам найти такие функции?

Что-то еще мне не хватает?

Ответы [ 9 ]

6 голосов
/ 05 сентября 2010

Чтобы повторить то, что я сказал в этих маленьких полях для комментариев. В частности, я никогда не говорил о inlin- ing :

// foo.h:
static void f() {
  // code that can't be inlined
}

// TU1 calls f
// TU2 calls f

Теперь и TU1, и TU2 имеют собственную копию f - код f находится в исполняемом файле два раза.

// foo.h:
inline void f() {
  // code that can't be inlined
}

// TU1 calls f
// TU2 calls f

Оба TU будут испускать специально отмеченные версии f, которые эффективно объединяются компоновщиком, отбрасывая все, кроме одного. Код f существует только один раз в исполняемом файле.

Таким образом, мы сохранили место в исполняемом файле .

3 голосов
/ 05 сентября 2010

Является ли inline просто рекомендацией для компилятора?

Да.

7.1.2 Спецификаторы функций

2 Объявление функции (8.3.5, 9.3, 11.4) со встроенным спецификатором объявляетвстроенная функция.Встроенный спецификатор указывает реализации, что внутренняя замена тела функции в точке вызова должна быть предпочтительнее обычного механизма вызова функции.Реализация не требуется для выполнения этой внутренней замены в точке вызова;однако, даже если эта встроенная замена не указана, все равно должны соблюдаться другие правила для встроенных функций, определенные в 7.1.2.

Например, из MSDN:

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

Обратите внимание:

3.2 Одно определениеrule

3 [...] Встроенная функция должна быть определена в каждой единице перевода, в которой она используется.

4 Встроенная функция должна быть определена в каждой единице перевода, в которой она используется, и должна иметь точно такое же определение в каждом случае (3.2).[Примечание: вызов встроенной функции может встретиться до того, как ее определение появится в блоке перевода.- примечание к концу] Если определение функции появляется в блоке перевода до ее первого объявления как встроенного, программа является некорректной. Если функция с внешней связью объявлена ​​встроенной в одной единице перевода, она должна быть объявлена ​​встроенной во всех единицах перевода, в которых она появляется;Диагностика не требуется. Встроенная функция с внешней связью должна иметь одинаковый адрес во всех единицах перевода.Статическая локальная переменная во внешней встроенной функции всегда ссылается на один и тот же объект.Строковый литерал в теле внешней встроенной функции - это один и тот же объект в разных единицах перевода.[Примечание: строковый литерал, появляющийся в выражении аргумента по умолчанию, не находится в теле встроенной функции только потому, что выражение используется в вызове функции из этой встроенной функции.—Конец примечания] Тип, определенный в теле внешней встроенной функции, является тем же типом в каждой единице перевода.

[Примечание: выделение мое]

TU в основномнабор заголовков плюс файл реализации (.cpp), который приводит к объектному файлу.

Должно ли это быть явно указано, когда у вас есть небольшая функция (я думаю, 1-4 инструкции?)

Абсолютно.Почему бы не помочь компилятору помочь вам генерировать меньше кода?Обычно, если часть пролога / эпилога несет больше затрат, чем встроенная, вынуждает компилятор их генерировать?Но вы должны, , абсолютно обязательно пройти эту статью GOTW, прежде чем приступить к встраиванию: ПОЛУЧИЛ # 33: Inline

Чтоесть ли другие преимущества при написании строки?

  • namespace s также может быть inline.Обратите внимание, что функции-члены, определенные в самом теле класса, являются встроенными по умолчанию.Так неявно генерируются специальные функции-члены.

  • Шаблоны функций не могут быть определены в файле реализации (см. FAQ 35.12 ), если, конечно, вы не предоставите явные экземпляры (для всех типов, для которых используется шаблон).- как правило, PITA IMO).См. Статью DDJ по Перемещение шаблонов из заголовочных файлов (Если вы чувствуете себя странно, прочитайте эту другую статью по ключевому слову export, которое было исключено из стандарта.)

Нужно ли указывать inline, чтобы уменьшить исполняемый файл размер, хотя компилятор (согласно википедии [я знаю, плохо ссылка]) должен найти такие функции сама

Опять же, как я уже сказал, как хороший программист, вы должны, когда можете, помочь компилятору. Но вот , что C ++ FAQ может предложить о inline. Так что будь осторожен. Не все компиляторы проводят такой анализ, поэтому вам следует прочитать документацию по их переключателям оптимизации. Например: GCC делает нечто подобное:

Вы также можете указать GCC попытаться интегрировать все «достаточно простые» функции в их вызывающие с помощью опции -finline-functions.

Большинство компиляторов позволяют в некоторой степени переопределять анализ соотношения затрат и выгод компилятора. Документацию MSDN и GCC стоит прочитать.

3 голосов
/ 05 сентября 2010

Является ли inline просто рекомендацией для компилятора?

Да. Но компоновщик нуждается в этом, если есть несколько определений функции (см. Ниже)

Должно ли это быть явно указано, когда у вас есть небольшая функция (я думаю, 1-4 инструкции?)

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

Какие еще преимущества есть при написании строки?

При правильном использовании остановит ошибки компоновщика.

нужно ли указывать inline, чтобы уменьшить размер исполняемого файла, даже если компилятор (согласно википедии [я знаю, плохая ссылка]) должен сам находить такие функции?

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

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

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

Множественное определение:

Файл: head.h

// Without inline the linker will choke.
/*inline*/       int  add(int x, int y) { return x + y; }
extern void test()

Файл: main.cpp

#include "head.h"
#include <iostream>

int main()
{
    std::cout << add(2,3) << std::endl;
    test();
}

Файл: test.cpp

#include "head.h"
#include <iostream>

void test()
{
    std::cout << add(2,3) << std::endl;
}

Здесь у нас есть два определения add (). Один в main.o и один в test.o

2 голосов
/ 05 сентября 2010
  1. Да. Это больше ничего.
  2. номер
  3. Вы намекаете компилятору, что это функция, которая вызывается много , где часть перехода к функции занимает много времени выполнения. Компилятор может решить разместить код функции там, где он вызывается, вместо нормальных функций. Однако, если функция встроена в x местах, вам нужно в x раз больше места нормальной функции.
  4. Всегда доверяйте вашему компилятору быть намного умнее себя на предмет преждевременной микрооптимизации.
2 голосов
/ 05 сентября 2010

На самом деле, встроенная функция может увеличить размер исполняемого файла, потому что код встроенной функции дублируется в каждом месте, где вызывается эта функция. Благодаря современным компиляторам C ++ inline в основном позволяет программисту поверить, что он пишет высокопроизводительный код. Компилятор решает сам, делать ли функцию встроенной или нет. Таким образом, написание текста позволяет нам чувствовать себя лучше ...

1 голос
/ 05 сентября 2010

Другое преимущество встраивания (обратите внимание, что фактическое встраивание иногда ортогонально использованию директивы «inline») имеет место, когда функция использует опорные параметры. Передача двух переменных в не встроенную функцию для добавления ее первого операнда ко второму потребует нажатия значения первого операнда и адреса второго, а затем вызова функции, которая должна вытолкнуть первый операнд и адрес второго , а затем добавьте предыдущее значение косвенно к перенесенному адресу. Если бы функция была встроена в строку, компилятор мог бы просто добавить одну переменную непосредственно к другой.

1 голос
/ 05 сентября 2010
  1. Да, он будет легко игнорировать ее, если будет считать, что функция слишком велика или использует несовместимые функции (возможно, обработка исключений).Кроме того, обычно есть настройка компилятора, позволяющая ему автоматически встроить функции, которые он считает достойными (/ Ob2 в MSVC).

  2. Это должно быть явно указано, если вы поместите определение функциив заголовочном файле.Что обычно необходимо для того, чтобы несколько единиц перевода могли воспользоваться этим.И чтобы избежать множественных ошибок определения.Кроме того, функции inline помещены в раздел COMDAT.Что говорит компоновщику, что он может выбрать только одно из нескольких определений.Эквивалент __declspec (selectany) в MSVC.

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

1 голос
/ 05 сентября 2010

Что касается этого:

И "inline" позволяет вам определять функцию несколько раз в программе.

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

Что касается других пунктов:

  1. inline - это просто рекомендация для компилятора, но есть директивы #pragma, которые могут принудительно включать любую функцию.
  2. Поскольку это всего лишь рекомендация, вероятно, безопасноявно попросите об этом и позвольте компилятору переопределить вашу рекомендацию.Но, вероятно, лучше вообще не указывать это и позволить компилятору принять решение.
  3. Упомянутое выше запутывание является одним из возможных преимуществ встраивания.
  4. Как уже упоминали другие, inline фактически увеличит размерскомпилированного кода.
0 голосов
/ 05 сентября 2010

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

http://www.parashift.com/c++-faq-lite/inline-functions.html

...