inline или static?
От: Rockoos  
Дата: 24.07.08 15:33
Оценка:
Всем привет!

У меня тут возник один вопрос, на который из моих знакомы уверенно так никто и не ответил...

Если объявить функцию inline в хедере, а реалезовать ее в cpp файле, будет ли функции после компиляции inline или компилятор сделает ее static?

Вопрос возник из таких размышлений, допустим у меня есть три файла:

finline.h
---------------
inline int f();


finline.cpp
---------------
#include "finline.h"
inline int f()
{
return <чего не будь>;
}

main.cpp
---------------
#include "finline.h"
int a = f();

inline функция прямой подстановки, допустим finline.cpp скомпилировался в объектник первым, при компиляции main.cpp компилятор подставит finline.h в main.cpp и скомпилирует main.obj. Но дело в том, что тело f() находится в finline.cpp, который уже скомпилирован и соотведственно по логике вещей никакой подстановки произойти не должо и линкер просто должен подставить адрес f() при линковке. Из этого следует вопрос inline должна быть полностью реализованна в хедере?
Re: inline или static?
От: MasterZiv СССР  
Дата: 24.07.08 16:45
Оценка:
Rockoos пишет:

> У меня тут возник один вопрос, на который из моих знакомы уверенно так

> никто и не ответил...
>
> Если объявить функцию inline в хедере, а реалезовать ее в cpp файле,
> будет ли функции после компиляции inline или компилятор сделает ее static?
>

Будет. Другой вопрос — что вы имеете в виду под
"функция будет inline". Я — что это функция, у которой есть модификатор inline.

> Вопрос возник из таких размышлений, допустим у меня есть три файла:


> inline функция прямой подстановки, допустим finline.cpp скомпилировался

> в объектник первым, при компиляции main.cpp компилятор подставит
> finline.h в main.cpp и скомпилирует main.obj. Но дело в том, что тело
> f() находится в finline.cpp, который уже скомпилирован и соотведственно
> по логике вещей никакой подстановки произойти не должо и линкер просто
> должен подставить адрес f() при линковке.

я что-то не понимаю. Если по вашей версии inline -функция — это функция
прямой подстановки, то при чем тут вообще линкер ?
До линкера функция дойти не должна уже, если она подставляется.
Тело компилятор подставляет (ну хотя бы как правило).

Из этого следует вопрос inline
> должна быть полностью реализованна в хедере?

Не обязательно, почему же ? Вот в том модуле, где она
определена, она будет как inline и возможно будет подставлена.
Если не подставлена, она не будет помещена в словарь глобальных
имен.

А в том модуле, где она не определена, ссылка на неё будет
сгенерена, и она потом в процессе линковки должна будет
разрешена линкером из словаря глобальных имён. Другое
дело, что вероятнее всего она там не будет найдена
линкером. Но это уже — дело десятое.

А, вы там написали, что она уже в хедере как inline описана...
Ну тогда она просто должна не найтись в каждом модуле,
использующем этот заголовок (и вызывающем функцию, естественно).
И все.
Posted via RSDN NNTP Server 2.1 beta
Re: inline или static?
От: Сергей Мухин Россия  
Дата: 24.07.08 16:45
Оценка: 1 (1)
Здравствуйте, Rockoos, Вы писали:

R>Всем привет!


R>У меня тут возник один вопрос, на который из моих знакомы уверенно так никто и не ответил...


R>Если объявить функцию inline в хедере, а реалезовать ее в cpp файле, будет ли функции после компиляции inline или компилятор сделает ее static?



может будет инлайн, может нет. Более того, даже если в .h объявить inline ответ будет такой же. Если компилятор не смог заинлайнить (замечу это делается иногда во время линковки), то он сажает каждое тело в свой коммунальный сегмент, и, после линковки, получается одно тело для ф-ии.
---
С уважением,
Сергей Мухин
Re: inline или static?
От: Erop Россия  
Дата: 24.07.08 16:46
Оценка: +1
Здравствуйте, Rockoos, Вы писали:

R>...inline должна быть полностью реализованна в хедере?


Да
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: inline или static?
От: Сергей Мухин Россия  
Дата: 24.07.08 16:50
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Rockoos, Вы писали:


R>>...inline должна быть полностью реализованна в хедере?


E>Да


Erop, я от тебя такого не ожидал
---
С уважением,
Сергей Мухин
Re[2]: inline или static?
От: MasterZiv СССР  
Дата: 24.07.08 17:30
Оценка: :)
Erop пишет:
> R>...inline должна быть полностью реализованна в хедере?
>
> Да

Чего за ерунду -то пишите ?

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

Тогда — ДА. А так — НЕТ.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: inline или static?
От: Erop Россия  
Дата: 24.07.08 18:43
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:


СМ>Erop, я от тебя такого не ожидал

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

Я всё ещё думаю, что ответил адекватно и достаточно полно
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: inline или static?
От: Сергей Мухин Россия  
Дата: 24.07.08 18:52
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Сергей Мухин, Вы писали:


СМ>>Erop, я от тебя такого не ожидал

E>Я всего лишь ответил на заданный вопрос. Я вообще, обычно в С++ отвечаю с целью помочь людям, не знающим чего-то в нашем запутанном языке

E>Я всё ещё думаю, что ответил адекватно и достаточно полно


1. по крайней мере MSDEV делает inline некоторые ф-ии которые реализованы не в header

2. я думаю можно привести ф-ию с телом в header которая не будет развернута в inline
---
С уважением,
Сергей Мухин
Re[4]: inline или static?
От: _Dinosaur Россия  
Дата: 24.07.08 19:19
Оценка:
Здравствуйте, Erop, Вы писали:

E>Я всё ещё думаю, что ответил адекватно и достаточно полно


адекватно — да, достаточно полно — нет

/* finline.h */
inline int f();
int e();

/* finline.c */
inline int f()
{
    int A = 3, B=4;
    return A*B;
}
int e()
{    return f();  }

/* main.c */
#include "finline.h"
inline int g()
{
    int B = 5, A = 7;
    return A*B;
}
int main(int argc, char** argv) {
    f();
    e();
    return g();
}


/* GCC -O2 */

    .file    "finline.c"
    .text
    .p2align 4,,15
.globl f
    .type    f, @function
f:
    pushl    %ebp
    movl    $12, %eax
    movl    %esp, %ebp
    popl    %ebp
    ret
    .size    f, .-f
    .p2align 4,,15
.globl e
    .type    e, @function
e:
    pushl    %ebp
    movl    $12, %eax
    movl    %esp, %ebp
    popl    %ebp
    ret
    .size    e, .-e
    .ident    "GCC: (GNU) 4.2.3 (4.2.3-6mnb1)"
    .section    .note.GNU-stack,"",@progbits


    .file    "main.c"
    .text
    .p2align 4,,15
.globl g
    .type    g, @function
g:
    pushl    %ebp
    movl    $35, %eax
    movl    %esp, %ebp
    popl    %ebp
    ret
    .size    g, .-g
    .p2align 4,,15
.globl main
    .type    main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl    -4(%ecx)
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ecx
    subl    $4, %esp
    call    f                # f();
    call    e
    addl    $4, %esp
    movl    $35, %eax        # g();
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size    main, .-main
    .ident    "GCC: (GNU) 4.2.3 (4.2.3-6mnb1)"
    .section    .note.GNU-stack,"",@progbits


тут еще генератора кода MSVC не хватает...
Завидую людям, которые могут себе позволить никуда не спешить.
Re[5]: Текущий смысл ключевого слова inline.
От: Erop Россия  
Дата: 24.07.08 19:36
Оценка: 2 (2) +1 :)
Здравствуйте, Сергей Мухин, Вы писали:

СМ>1. по крайней мере MSDEV делает inline некоторые ф-ии которые реализованы не в header

СМ>2. я думаю можно привести ф-ию с телом в header которая не будет развернута в inline
Видимо тебе интересен более полный ответ, чем топикстартеру.
IMHO он таков.

Когда-то давно, когда компиляторы ещё не были так продвинуты как сейчас, им тербовались подсказки со стороны программиста, чтобы лучше оптимизировать программу.
Примером такой подсказки является слово register.
Слово inline имеет в чём-то похожую судьбу. Когда-то давно слово inline обозначало инструкцию компилятору попробовать использовать знание определения функции в точке её вызова. Например, просто "подставив" код функции в место вызова, или ещё как-то.
При этом, для того, чтобы эта оптимизация была действительно полезной, для inline функций несколько ослабили проверку ODR. То есть определение iline функции могло быть в нескольких единицах трансляции, но при этом все определения должны были совпадать и быть эквивалентны. Это чем-то похоже на определения классов, например.
Как компиляторы и линкеры выкручивались из таких неудобных условий -- вопрос отдельный. Одни, например, помещали определения inline функциий не во все единицы трансляции (вернее не во все объектники), а только в некоторые, выбираемые по каким-нибудь эвристикам. Другие помечали попавшее в объектник определение inline функции, как блок кода, который может быть сдублирован в другом объектнике, и т. д.
Короче говоря выкручивались и выкручиваются, оставляя заботу о совпадении и эквивалентности определений inline функции доступных из разных единиц трансляции на совести программиста. Это, кстати, небезопасно, так как черевато всякими уродскими проблемами.

Например, в одной единице трансляции мы можем написать что-то вроде
struct TableEntry {
   int Id;
   std::string Name;
} table[] = {
    { 1, "понедельник" },
    { 2, "вторник" }
}
а в другой что-то вроде
struct TableEntry {
   std::string Name;
   int Id;
} table[] = {
    { "We", 2 },
    { "I", 1 }
}
ну и нарваться на то, что если ~TableEntry не подставится, и вызовется из "неродной" единицы трансляции, то программа будет совершенно мистически падать при отгрузке.

Возможны и более тонкие эффекты, конечно.


Теперь, после экскурса в историю слова inline и обзора особенностей его относительно честной реализации, можно перейти к сегодняшнему дню. Хотя бывали и бесчестные реализации, конечно. Например такие:
#define inline static

Сегодня любой нормальный компилятор, и многие линкеры тоже, используют в точке вызова информацию о теле всех функций до определения которых они могут добраться. Так что единственный существенный смысл слова inline, который остался -- это ослабление проверки ODR для inline функций.
В этом смысле больше нет смысла писать про функцию inline, и не публиковать в хедере её определение. Хотя, конечно, именно подстановку функции в месте вызова слово inline как не гарантировало, так и не гарантирует

Так что на менее глубоком уровне понимания всех этих не особо нужных подробностей, простое утверждение, что опроеделение inline функции всегда следует размещать в хедере совсем и не плохо
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
inline register
Re[5]: inline или static?
От: Erop Россия  
Дата: 24.07.08 19:47
Оценка: +2
Здравствуйте, _Dinosaur, Вы писали:

_D>адекватно — да, достаточно полно — нет

У любого вопроса есть автор и уровень. Уровень часто читается из вопроса, автор может уточнить или переспросить

_D>[ccode]


_D> call f # f();

_D> call e
_D> addl $4, %esp
_D> movl $35, %eax # g();
_D> popl %ecx
_D> popl %ebp
_D> leal -4(%ecx), %esp
_D> ret
_D>[/code]

_D>тут еще генератора кода MSVC не хватает...

_D>)
Ну это ничего не доказывает, вообще-то
1) Сейчас компиляторы умеют делать inline-подстановки на этапе линковки. Так что есть вполне реальный расклад, когда твоя main сократится до кода, эквивалентного
return 12;

2) Никто из них (компиляторов) не гарантирует, что какая-то конкретная подстановка будет сделана.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: inline или static?
От: _Dinosaur Россия  
Дата: 24.07.08 20:16
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>У любого вопроса есть автор и уровень. Уровень часто читается из вопроса, автор может уточнить или переспросить

+1

[]
E>Ну это ничего не доказывает, вообще-т
?
E>1) Сейчас компиляторы умеют делать inline-подстановки на этапе линковки.
Кстати, хотел бы взглянуть на генерируемый ими код...
E>Так что есть вполне реальный расклад, когда твоя main сократится до кода, эквивалентного
return 12;

вроде так
return 35;
Завидую людям, которые могут себе позволить никуда не спешить.
Re: inline или static?
От: Rockoos  
Дата: 24.07.08 20:24
Оценка:
Всем громадное спасибо!
Re: inline или static?
От: Vain Россия google.ru
Дата: 24.07.08 20:41
Оценка:
Здравствуйте, Rockoos, Вы писали:

R>finline.h

R>---------------
R>inline int f();


R>finline.cpp

R>---------------
R>#include "finline.h"
R>inline int f()
R>{
R> return <чего не будь>;
R>}

R>main.cpp

R>---------------
R>#include "finline.h"
R>int a = f();

R>inline функция прямой подстановки, допустим finline.cpp скомпилировался в объектник первым, при компиляции main.cpp компилятор подставит finline.h в main.cpp и скомпилирует main.obj. Но дело в том, что тело f() находится в finline.cpp, который уже скомпилирован и соотведственно по логике вещей никакой подстановки произойти не должо и линкер просто должен подставить адрес f() при линковке. Из этого следует вопрос inline должна быть полностью реализованна в хедере?

Всё по порядку.
Для современных компиляторов по-умолчанию не важен порядок компиляции cpp файлов, т.к. всю работу с подстановкой они делают до стадии линковки. При этом есть в некоторых компиляторах режим в котором часть работы компилятора ложиться на компоновщик, но эту тему пока мы оставим.
Далее, если функция f() имеет тело и в finline.cpp/.o и в main.cpp/.o, то адреса у них не обязаны совпадать. Если только вы не пытаетесь её экспортировать (ключевое слово extern), что значит, что функция будет подлинкована на стадии компоновки, т.к. станет "видна" другим модулям, код в которых её вызывает. По умолчанию, каждое объявление функции считается её экспортом, до тех пор пока в том же модуле компилятор не "встретит" её тело. Далее, вы указываете ключевое слово inline на теле функции (кстати на объявлении функции модификатор inline не имеет силы), указывая что вы желаете, чтобы компилятор вставил тело функции в модуль где этот inline приставлен к функции, что возможно и происходит, а может и нет, т.к. inline — это "совет" компилятору, а не "команда".
Далее, у меня получилось юзать такую штуку как extern+inline (extern в паре с inline на теле функции), т.е. использования одновременно и экспортирования и подстановки, что говорит о том что inline функция обычно "реализуется" в хедере, но с этой конструкцией вроде как и не обязана.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: inline или static?
От: Erop Россия  
Дата: 24.07.08 22:16
Оценка: +1
Здравствуйте, Rockoos, Вы писали:

R>Всем громадное спасибо!

Для "спасибо" тут есть кнопки
А так, пожалуйста. Обращайся
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: inline или static?
От: gear nuke  
Дата: 25.07.08 00:25
Оценка:
Здравствуйте, Vain, Вы писали:

V>у меня получилось юзать такую штуку как extern+inline (extern в паре с inline на теле функции)


У меня тоже получалось... в некоторых случаях Internal Compiler Error
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[2]: inline или static?
От: Maxim S. Shatskih Россия  
Дата: 25.07.08 16:23
Оценка: -1
MZ>А в том модуле, где она не определена, ссылка на неё будет
MZ>сгенерена, и она потом в процессе линковки должна будет
MZ>разрешена линкером из словаря глобальных имён. Другое
MZ>дело, что вероятнее всего она там не будет найдена
MZ>линкером.

Точно не будет, inline в частности несет на себе всю семантику static, и функция не глобал.

Я бы не стал вообще такой код писать. И, скорее всего, компиляция обломится, ибо функция не имеет тела при компиляции второго файла.
Занимайтесь LoveCraftом, а не WarCraftом!
Re[3]: Немного не так...
От: Erop Россия  
Дата: 25.07.08 16:39
Оценка:
Здравствуйте, Maxim S. Shatskih, Вы писали:

MSS>Точно не будет, inline в частности несет на себе всю семантику static, и функция не глобал.

1) Это не правда. Связанность функции и то, что она помечена, как inline никак не связано.
Например такой код
// 1.h
inline int getCount()
{
    static int seed = 0;
    return ++seed;
}
//  1.cpp
const int id1 = getCount();

//  2.cpp
const int id2 = getCount();
валиден, за исключением того, что не известно какие значения получит id1 и id2. Известно только, что разные...

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

MSS>Я бы не стал вообще такой код писать. И, скорее всего, компиляция обломится, ибо функция не имеет тела при компиляции второго файла.

Я бы тоже, но совсем по другой причине
Автор: Erop
Дата: 24.07.08
. На совреенных компиляторах нет никакого смысла указывать, что функция inline, если нет нужды публиковать её определение для нескольких единиц трансляции
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
inline
Re[4]: Немного не так...
От: Maxim S. Shatskih Россия  
Дата: 26.07.08 20:28
Оценка: +1 :)
E>1) Это не правда. Связанность функции и то, что она помечена, как inline никак не связано.
E>Например такой код [c]// 1.h

Отстал я, видимо, С/Э писали, что inline есть всегда static + кое-что еще (сама инлайн-подстановка)
Занимайтесь LoveCraftом, а не WarCraftом!
Re: inline или static?
От: igna Россия  
Дата: 28.07.08 06:33
Оценка:
Здравствуйте, Rockoos, Вы писали:

R>Из этого следует вопрос inline должна быть полностью реализованна в хедере?


Inline-функция должна быть определена в каждой единице трансляции, в которой она используется, причем все ее определения должны совпадать. Самый простой способ выполнить это требование — определять inline-функцию в том же заголовочном файле, в котором она объявляется.

PS. При компиляции твоего примера, а именно при компиляции main.cpp компилятор должен выдать сообщение об ошибке; впрочем не удивлюсь, если он этого не сделает.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.