Re[4]: Феерия с inline в C99 и GCC 5.1
От: watchmaker  
Дата: 03.07.15 18:58
Оценка: 144 (7)
Здравствуйте, Кодт, Вы писали:


К>А компилятор не должен ли действовать как-то согласованно: или выкидывать-и-инлайнить, или выносить-и-вызывать (или выносить-но-всё-равно-инлайнить)?

К>Что за прикол такой, implementation-defined, сделать висячую ссылку?

А это просто неправильное использование inline. Хотя, действительно, с первого взгляда это может быть немного неочевидно.

Нет смысла внутри .c файла писать inline void foo() {...} если это единственная реализация foo. На возможность встраивания функции это никак не влияет (в документации же написано об игнорировании этого устаревшего смысла inline, в отличии от всяких __attribute__((always_inline)) ; как максимум наличие inline может случжить лишь рекомендацией компилятору обратить внимание на это место). На visibility наличие inline также не влияет. А других ролей у inline тем более нет.


Основное и правильное использование inline — это писать его в заголовочных файлах.
И компилятору при этом сообщается примерно следующее: «вот есть такая функция, возможно её стоит встроить, а так как для встраивания нужен ещё и исходный код, то вот он; а если решишь, что встраивание не даст пользы — вызывай функцию как обычно». Поэтому в .h файле пишется что-то вроде
inline void foo() 
{
  // реализация
}

И везде, где подключён файл .h можно вызывать функцию foo как обычно, но при этом компилятору доступна не только сигнатура, но и реализация, так что он может делать оптимизации её тела по месту.
Ну и как обычно, в одном из .c файлов даётся определение
extern inline void foo();
Причём, как видно, тут просто сообщается о том, какой объектный файл будет предоставляют функцию, а её код автоматически берётся из .h файла.

В общем, inline в c99 вполне рационально устроен. Главное его в .c не писать (без static или extern) — он там бессмысленнен и приводит к созданию такого рода тем.


Кстати говоря, в C++ есть механизмы, который работают точно также. Например,
class Bar {
   static const int x = 4;
};

По стандарту недостаточно написать это в .h файле, но нужно дополнительно в одном из .cpp файлов сделать инстанциирование
const int Bar::x;
И причём, если этого не сделать, то код программы может как собраться (если компилятор встроит все места использования x), так и не собраться, если компилятору где-то захочется взять реальную переменную (а захотеться ему может внезапно по совершенно разным причинам).
То есть поведение практически совпадает с поведением inline в c99, только в одном случае это статические члены класса, а другом — функции. Остальное одинаково: «вот есть член/функция, встраивай если хочешь».


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