Прототип вбудованої функції проти звичайної декларації проти прототипу

Яка різниця між вбудованою функцією, а потім основною, як така:

inline double cube(double side)
{
   return side * side * side;
}

int main( )
{
    cube(5);
}

vs просто оголосити функцію регулярно, як:

double cube(double side)
{
   return side * side * side;
}

int main( )
{
    cube(5);
}

проти прототипу функцій?

double cube(double);

int main( )
{
    cube(5);
}

double cube(double side)
{
   return side * side * side;
}
3
додано Автор Kerrek SB, джерело
Ви мали на увазі cube (5); ?
додано Автор log0, джерело
Я думав, що так.
додано Автор log0, джерело

4 Відповіді

Функція inline може бути визначена в декількох одиницях перекладу (cpp file + includes) і є підказкою для компілятора для вбудовування функції. Він зазвичай розміщується у заголовку, що збільшує час компіляції, але може призвести до швидшого коду. Це також дозволяє використовувати цю функцію з багатьох підрозділів компіляції.

//cube.h
inline double cube(double side)
{
   return side * side * side;
}

//cube.cpp
int main( )
{
    cube(5);
}

Визначення його регулярно є звичайним методом, де він (зазвичай) визначається у файлі CPW і зв'язаний з ним. Це нелегко використовувати з інших компіляційних одиниць.

//cube.cpp
double cube(double side)
{
   return side * side * side;
}

int main( )
{
    cube(5);
}

Прототип дозволяє вам повідомити компілятору, що функція буде існувати під час посилань, навіть якщо вона ще не існує. Це дозволяє головному викликати цю функцію, навіть якщо вона ще не існує. Як правило, прототипи знаходяться у заголовках, тому інші компіляційні підрозділи можуть викликати функцію, не визначаючи її самі. Це має найшвидший час компіляції, і ця функція легко використовується з інших одиниць компіляції.

//cube.h
double cube(double);

//cube.cpp
int main( )
{
    cube(5);
}

double cube(double side)
{
   return side * side * side;
}
6
додано
Відмінне та дуже зрозуміле пояснення, сер/маам. Дуже дякую!
додано Автор iggy2012, джерело
Останній приклад - це невизначена поведінка без необхідності діагностики, якщо cube.h включається як cube.cpp , так і іншим блоком перекладів. Функція не може бути inline в одному блоці та не вбудована в іншу.
додано Автор M.M, джерело
У другому прикладі було б непоганою практикою позначити функцію як внутрішню зв'язок, щоб уникнути випадкової невизначеною поведінки у випадку, якщо інша частина проекту також виконує функцію cube
додано Автор M.M, джерело
... можна визначити в одній компіляційній одиниці (cpp file + includes) декілька разів - чи мали на увазі різні одиниці компіляції?
додано Автор anatolyg, джерело
@MooingDuck: анатоліг правильний, функція inline може бути визначена лише один раз у блоці перекладу, навіть якщо її можна визначити кілька разів у програмі, не порушуючи ODR.
додано Автор David Rodríguez - dribeas, джерело
Ні, inline дозволено порушувати ODR, наприклад шаблони. В іншому випадку, було б важко додати вбудований в заголовок, і якщо воно не було в заголовку, дурні компілятори не могли вставити це!
додано Автор Mooing Duck, джерело
О, вірно, я помилявся. Забули про включення охоронців.
додано Автор Mooing Duck, джерело
@ M.M: Виправлено додатковий inline в останньому зразку, спасибі. Ви правильні про внутрішні зв'язки, але це додаткова складність, яка не є надзвичайно актуальною для відповіді.
додано Автор Mooing Duck, джерело
Чому це не прийнято як відповідь, я дивлюсь.
додано Автор Felype, джерело

Продуктивність мудрих, вони все одно однакові, оскільки inline є лише натяком для компілятора. Якщо використовується відокремлення декларації/визначення, а визначення знаходиться в іншому блоці перекладу, для компілятора буде складніше вбудовувати його (але існують реалії, які це роблять).

Різниця з виконанням функції inline чи ні, полягає в тому, що лінкер не скаржиться, якщо він побачить однакове вбудоване визначення для функції більше одного разу.

1
додано

Програма 3 складається точно так само з g ++ -S-O3 $ file.cc . Крім другого прикладу, де визначення double cube (double side) все ще існує в не введеній формі, хоча вкладено в int main() .

_main:
pushl   %ebp
movl    $16, %eax
movl    %esp, %ebp
subl    $8, %esp
andl    $-16, %esp
call    __alloca
call    ___main
leave
xorl    %eax, %eax
ret
1
додано
Різниця, яку ви вказуєте, - це деталізація реалізації, деякі компілятори генерують всі функції завжди, навіть якщо вони насправді вставляються, оскільки ви маєте право отримати адресу функції inline , і компілятор не може знати під час обробки функції, якщо пізніше в тій самій TU, яку буде запропоновано функціональна адреса.
додано Автор David Rodríguez - dribeas, джерело
@Давид точно.
додано Автор log0, джерело

Коли ви декларуєте функцію вбудованої лінії, компілятор намагається прискорити код, більш-менш копіюючи тіло функції, де він викликається. Це лише пропозиція, і компілятор приймає рішення, якщо це можливо.

Я не знаю, що станеться в 3-му прикладі. Я думаю, це буде залежати від використовуваної ланцюга інструменту.

0
додано
Останній - це лише прототип функції перед основним (). Всі вони, здається, працюють однаково, але я, здається, не розумію, яка різниця.
додано Автор iggy2012, джерело
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147