-1 / 25 / 4
Регистрация: 27.11.2017
Сообщений: 375
|
|
1 | |
Inline функция или нет29.11.2017, 22:52. Просмотров 2076. Ответов 25
Метки нет Все метки)
(
Как известно ключевое слово inline - это всего лишь просьба к компилятору оформить данную функцию как встраиваемую, а вот выполнит он эту просьбу или нет, ведомо только ему одному.
Вопрос такой, можно ли в принципе узнать удовлетворил ли он наше ходатайство о присвоении той или иной функции звания inline, или же он это ходатайство отклонил? И второй вопрос (если, конечно, ответ на первый будет положительным): Как это сделать в принципе?
0
|
|
29.11.2017, 22:52 | |
Inline функции - на сколько должна быть маленькая функция, чтоб она подошла под inline?
inline функция
|
|
С чаем беда...
![]() ![]() 8493 / 4216 / 1168
Регистрация: 18.10.2014
Сообщений: 9,130
|
|
29.11.2017, 23:16 | 2 |
Эффект ключевого слова
inline двояк. Это, во-первых, эффект для самой функции, и, во-вторых, эффект для вызовов этой функции.Встраивание кода функции в место вызова - это именно эффект второй группы. К самой функции он никакого отношения не имеет. Именно о встраивании вызовов вы ходатайствуете ключевым словом inline . Решение о встраивании/невстраивании кода в точке вызова принимается компилятором для каждого вызова отдельно и независимо. Какие-то вызовы могут встроиться, а какие-то - не встроиться. Узнать, какие вызовы встроились, а какие нет, можно только посмотрев на сгенерированный компилятором код. Более того, компилятор имеет полное право встраивать вызовы функций, не объявленных inline . То есть связь с inline тут очень нечеткая.Что касается эффекта для самой функции - он к встраиванию кода никакого отношения не имеет вообще. Эффект inline сводится только к тому, что для данной функции изменяется Правило Одного Определения (One Definition Rule): inline-функцию (в отличие от обычных функций) разрешается определять в программе несколько раз, в разных единицах трансляции. Здесь нет никакого "ходатайства" - это эффект всегда проявляется гарантированно и безусловно.То есть "звание inline " такая функция получает всегда и безусловно. Но это не гарантирует, что все вызовы этой функции будут встраиваться. Может быть вообще ни один не встроится.
1
|
Заклинатель змей
603 / 502 / 212
Регистрация: 30.04.2016
Сообщений: 2,410
|
|
29.11.2017, 23:20 | 3 |
Просто Саша, присоеденюсь к мнениюTheCalligrapher. Если верить Шилдту, то встраивания нет для функций с if/else, for, goto
0
|
С чаем беда...
![]() ![]() 8493 / 4216 / 1168
Регистрация: 18.10.2014
Сообщений: 9,130
|
|
29.11.2017, 23:31 | 4 |
А вот это как раз таки типичная шилдтовская белиберда. Алгоритмы принятия решения о встраивании, разумеется, у каждого компилятора свои. Одна существенная преграда для встраивания очевидна - это рекурсия. Однако и рекурсию можно встраивать до некоей фиксированной глубины.
Проблемы с встраиванием также могут быть у функций, содержащих вызовы alloca , setjmp/longjmp . Помнится были еще какие-то менее очевидные проблемы с обработкой исключений.Но "if/else, for, goto" - это из разряда "это было давно и неправда"... Добавлено через 4 минуты Многие компиляторы, кстати, предоставляют средства для отслеживания того, встроились ли вызовы inline функций. Для GCC это предупреждение выключается через -Winline . Для MSVC, насколько я помню, аналогичные предупреждения генерируются для __forceinline функций.
1
|
-1 / 25 / 4
Регистрация: 27.11.2017
Сообщений: 375
|
|
29.11.2017, 23:39 [ТС] | 5 |
Может быть он и двояк, я тут спорить не буду, но тока укажу на тот эффект, с которым Вы все согласитесь.
Коли сделали мы функцию inline функцией, то все, во-первых мы распрощались с ее прототипами, и обязаны размещать определение такой функции выше по тексту в том файле, куда мы хотим ее пристроить. А что там делает компилятор - это интересно, я и задал то поэтому вопрос, можно или нет оценить как сработал компилятор в том или в другом случае. Добавлено через 6 минут Кстати, хочу обратить внимание не на вот эти else и goto, а вот на такой факт: В учебниках напрочь отсутствует такая тема inline функции и перегрузка. Вот что Вы можете сказать по этому поводу? Вот согласитесь, что вот так с ходу не определишь, разрешается ли перегружать inline функцию, а если разрешается, то как встраивается то или другое. Ведь на стадии компиляции не очень то определишь, что будет вызвано на стадии выполнения.
0
|
С чаем беда...
![]() ![]() 8493 / 4216 / 1168
Регистрация: 18.10.2014
Сообщений: 9,130
|
|
29.11.2017, 23:48 | 6 |
С формальной токи зрения это не совсем верно. Спецификация языка лишь говорит, что inline-функция должна быть определена во всех единицах трансляции, в которых она используется, и везде определена одинаково. Требования определять ее именно "выше по тексту" нет. Более того, ремарка в тексте стандарта специально подчеркивает это: "[ Note: A call to the inline function or a use of the inline variable may be encountered before its definition appears in the translation unit. —end note ]". При желании, вы можете сверху воспользоваться прототипом (с
inline ), а определение поместить вниз.Не понятно, о чем речь. Никаких особенностей, связанных с inline, перегрузка (overloading) не имеет вообще. Не ясно, откуда взялась "стадия выполнения". Перегрузка функций всегда полностью разрешается (через процесс overload resolution) на стадии компиляции. Всегда на стадии компиляции ясно, какая функция будет вызываться.
1
|
-1 / 25 / 4
Регистрация: 27.11.2017
Сообщений: 375
|
|||||||||||
29.11.2017, 23:52 [ТС] | 7 | ||||||||||
Кстати вот Стивен Прата в своем учебнике утверждает, что для того чтобы функция стала inline нужно выполнить хотя бы одно из двух:
1) Предварить ОПРЕДЕЛЕНИЕ этой функции словом inline 2) Предварить ОБЪЯВЛЕНИЕ этой функции словом inline (я так понимаю это использовать прототип с inline) Возникает вопрос зачем использовать inline с прототипом, если определение должно стоять выше по тексту. Или он что имеет в виду, что inline функцию можно разместить в отдельном файле, а затем дотянуться до нее просто использовав inline с ее прототипом. Попробовал и вот что вышло: 1) вариант
2) вариант (inline уже только в прототипе)
0
|
С чаем беда...
![]() ![]() 8493 / 4216 / 1168
Регистрация: 18.10.2014
Сообщений: 9,130
|
||||||
30.11.2017, 00:00 | 8 | |||||
Не должно.
Оба варианта некорректны
1
|
-1 / 25 / 4
Регистрация: 27.11.2017
Сообщений: 375
|
|
30.11.2017, 00:22 [ТС] | 9 |
Ну почему он не должен появляться на уровне блока, если во-первых тоже работает, а во-вторых, зачем он на внешнем, если он нужен только в функции main?
Куда тогда деть принцип минимальных привилегий? И опять же самый главный вопрос. Ну работает оно и в моем и в Вашем варианте и проверил будет работать даже если функцию display разместить в отдельном файле. Но то что имеет место inline не факт. Может оно сработало, как вызов обычной функции, хотя по всем канонам, вот такая функция просто обязана быть встраиваемой.
0
|
С чаем беда...
![]() ![]() 8493 / 4216 / 1168
Регистрация: 18.10.2014
Сообщений: 9,130
|
||||||
30.11.2017, 00:38 | 10 | |||||
"Тоже работает" - это ничего не значит. Если ваш компилятор при компиляции хоть как-то ругнулся на локальное объявление с
inline , то он своею задачу выполнил - вас предупредил. А дальше - ваши проблемы. С точки зрения С++ поведение программы не определено.А если ваш компилятор вообще никак не ругнулся, то это значит, что либо вы его неправильно сконфигурировали (т.е. он не работает в режиме стандартного С++ вообще), либо в компиляторе сидит баг. GCC исправно ругается на такое: http://coliru.stacked-crooked.... bf0c1dad6b
Код
g++ -std=c++17 -pedantic-errors main.cpp main.cpp: In function 'int main()': main.cpp:3:28: error: 'inline' specifier invalid for function 'display' declared out of global scope [-Wpedantic] inline auto display() -> void; ^~~~ Это опять не имеет никакого отношения к С++. Если функция объявлена inline , то она должна быть определена в этой же единице трансляции. А то, что "будет работать если разместить в отдельном файле" - это уже глюки реализации, к С++ никакого отношения не имеющие. Это по каким это "канонам" такой вызов обязан быть встраиваемым? В С++ нет никаких канонов, которые бы могли гарантировать встроенность вызова.
1
|
-1 / 25 / 4
Регистрация: 27.11.2017
Сообщений: 375
|
|
30.11.2017, 01:02 [ТС] | 11 |
Никак он не ругается и никаких предупреждений не дает (MS Visual Studio 2017)
Что значит снаружи? В C++ все функции определяются снаружи, но это ведь не значит, что доступ к ним нужно давать везде, где только можно. Так мы докатимся и до того, что все переменные глобальными сделаем. Ну каноны такие - функция всего одна строка, да и то простейшая, конечно я тут на уровне интуиции говорю. Ну а что на самом деле, если эта простота не inline, то что тогда вообще может быть inline? Вот пока, что понял, так это то, что inline дает возможность размещать такие функции в заголовках, а все остальное на уровне любит - не любит, или, как говорится - ОТ ЛУКАВОГО. Добавлено через 3 минуты Самое то главное не сделано. Ну понятно, компилятор сработает, как написали его разработчики, следовали они стандарту или не следовали - это другой вопрос. Понятно, что нельзя требовать от программы (компилятора), чтобы он сделал что-то сверх того, что в него вложили, но вот что конкретное он сделал (обинлайнил он эту функцию или же нет) мы вроде знать имеем право. Но тут то как раз везде, что в учебниках, что в сети, тишина глухая, как на кладбищенском погосте. Добавлено через 4 минуты Да и еще вот нарыл, что #pragma inline-recursion позволяет инлайнить и рекурсивные функции до 16 уровней. Ещё какая-то прагма позволяет понижать число этих уровней. И не будут инлайнится те функции, обращение к которым происходит через указатель.
0
|
С чаем беда...
![]() ![]() 8493 / 4216 / 1168
Регистрация: 18.10.2014
Сообщений: 9,130
|
|
30.11.2017, 01:52 | 12 |
Баг компилятора.
К функциям с внешним связыванием доступ в любом случае есть везде, где только можно. Механизмы "ограничения доступа" сводятся к private и protected на уровне класса и static /unnamed namespace на уровне единицы трансляции, но это не наша тема.Не вижу аналогии. С переменными у нас есть выбор - они бывают локальными. Локальных функций в С++ нет. В одну строку можно запихнуть очень много кода. И критерии, используемые, например, GCC обычно выглядят несколько по-иному и зависят от уровней оптимизации. Например, статическая функция, вызываемая только один раз, обычно будет встроена всегда, независимо от размера. С остальными критерий может быть таков - общий размер кода не должен увеличиться. И т.д. и т.п. Запустите GCC с -Winline - и он сам будет объяснять вам, почему он что-то не заинлайнил.
2
|
-1 / 25 / 4
Регистрация: 27.11.2017
Сообщений: 375
|
|
30.11.2017, 02:04 [ТС] | 13 |
Нет, тут до связывания дело не доходит. Оно здесь вообще ни сбоку припеку и правильно Вы говорите - это не наша тема.
Локальных функций, конечно нет, зато есть локальные области видимости. Вот последнее более интересно, значит все таки, кто то реализовал такую штуку. Тогда разумеется вопрос сужается. Вы может быть знаете тогда какой ключ в MS Visual Studio отвечает за подобную функциональность?
0
|
С чаем беда...
![]() ![]() 8493 / 4216 / 1168
Регистрация: 18.10.2014
Сообщений: 9,130
|
||||||
30.11.2017, 04:08 | 14 | |||||
В MS Visual Studio для этого следует использовать
__forceinline вместо inline , а также включить предупреждение C4714 (уровень 4). То есть либо поднять уровень предупреждений в настройках проекта до 4, либо наоборот понизить собственный уровень C4714 до 1
C4714 на вызовы __forceinline функций, которые он по какой-то причине не сумел встроить. Объяснений "почему" он однако не предоставляет - надо разбираться самому.В описании C4714 перечислены возможные причины.
1
|
Велосипедист...
349 / 216 / 73
Регистрация: 15.12.2015
Сообщений: 785
|
|||||||||||
30.11.2017, 04:18 | 15 | ||||||||||
Пока мы еще совсем не съехали с темы, хочу воспользоваться моментом и уточнить 2 вещи:
1. Правда ли, что ключевое слово inline можно опустить в определении inline-функции, если выше есть объявление ( прототип ) этой функции?
inline ? У меня сейчас двоякое мнение:__1) с одной стороны, это UB, ведь если компилятор действительно встроит такую функцию, тогда ее существовать не будет в принципе. __2) с другой стороны, как мне кажется, если компилятор встретит выражение, где адрес функции ( которую пометили как inline ) попытаются присвоить указателю на функцию, то такая функция встроенной не станет ( спецификатор inline будет проигнорирован ).
TheCalligrapher
0
|
2706 / 1875 / 554
Регистрация: 05.06.2014
Сообщений: 5,447
|
|
30.11.2017, 04:35 | 16 |
С чего бы? Встраиваем копию функции в каждую точку ее вызова, еще одну копию функции заводим чтоб было на что указывать указателю, и всего делов.
1
|
Велосипедист...
349 / 216 / 73
Регистрация: 15.12.2015
Сообщений: 785
|
|
30.11.2017, 04:39 | 17 |
Renji, Это так есть на самом деле, или это Ваше предположение?)
0
|
2706 / 1875 / 554
Регистрация: 05.06.2014
Сообщений: 5,447
|
|
30.11.2017, 04:40 | 18 |
Предположение. В нутро компилятора не заглядывал, но такой вариант видится мне наиболее логичным.
1
|
С чаем беда...
![]() ![]() 8493 / 4216 / 1168
Регистрация: 18.10.2014
Сообщений: 9,130
|
|
30.11.2017, 04:41 | 19 |
Правда. По крайней мере именно так я воспринимаю намерение авторов стандартя языка.
Можно. Вы продолжаете путать две вещи, о которых я говорил ранее: влияние inline на саму функцию и влияние inline на вызовы этой функции в коде.На саму функцию inline влияет только одним образом: он позволяет определять ее много раз в программе (без возникновения при этом ошибки линкера). Этот эффект inline есть всегда, то есть ни о каком игнорировании inline не может быть и речи. К "указателям" это не имеет никакого отношения.Что касается вызовов (и других ссылок) на функцию из основного кода - то это совсем другая история. Одни вызовы могут быть встроены, другие - не встроены. Если какие-то вызовы отказались не встроены, то для обслуживания таких вызовов компилятором будет сгенерировано обычное тело той же самой функции, единственное на всю программу. Вот точно так же и с указателями: если где-то в коде кто-то создает указатель на inline функцию, то по этой причине будет сгенерировано обычное тело функции и этот указатель будет указывать на него. Это однако никак не мешает остальным вызовам этой функции продолжать спокойно встраиваться Таким образом никакого UB тут нет. И никакого игнорирования inline тут тоже нет. Что с указателями, что без, все работает по одной и той же схеме. В каждой точке кода решение принимается индивидуально: если компилятор захотел/сумел выполнит встраивание, он его выполняет, а в остальных случаях идет работа с обычным телом функции. В том числе, если в месте вызова функции через указатель "особо умный" компилятор точно знает, на какую функцию этот указатель указывает, то он может сделать прямой вызов и выполнить встраивание. Эта логика распространяется и на объявление виртуальных функций как inline .
1
|
Тематические курсы и обучение профессиям онлайн Профессия Разработчик на C++ (Skillbox) Архитектор ПО (Skillbox) Профессия Тестировщик (Skillbox) |
Велосипедист...
349 / 216 / 73
Регистрация: 15.12.2015
Сообщений: 785
|
|
30.11.2017, 05:06 | 20 |
Да, это так. С первого раза до меня не дошло...)
То есть, если все вызовы функции оказались встроенными и надобности в генерировании тела функции не возникло, то оно сгенерировано не будет? ( Если да, можно не отвечать. ) Спасибо.
0
|
30.11.2017, 05:06 | |
Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.
Inline функция в Debug режиме virtual inline функция-член каласса inline функции vs инструкции inline функций Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |