| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Для новичков > inline и define - выбор |
| Автор: Riply 23.7.2008, 17:23 | ||||
| Здравствуйте ! Допустим, у нас есть такая функция, которую мы собираемся вызывать так много раз, что и не сосчитаешь
Пробуем написать ее аналог, используя "дефайны"
Какой из этих двух вариантов (если конечно они не содержат ошибок) предпочтительней для использования ? (первый в три раза медленнее второго, но второй как-то ненадежно выглядит Например, в нем используется выражение " ((_pus)->Length = _cbLen) * 0 " Всегда ли его левый сомножитель будет "вычисляться" или, при некоторых условиях, может игнорироваться ? |
| Автор: Riply 23.7.2008, 17:38 | ||
Попробовала запустить не из под среды. Результат тот же: соотношение один к трем. Сейчас попробую посмотреть в CPU-шке, правда я там себя не очень уверенно чувствую |
| Автор: W4FhLF 23.7.2008, 17:49 |
| Выложи два варианта в виде exe в релиз сборке. Посмотрим на оптимизацию. |
| Автор: Partizan 23.7.2008, 17:58 |
| ммм...насколько я знаю компилятор оставляет за собой право не инлайнить функцию по своему усмотрению даже тогда когда явно указан модификатор __inline... |
| Автор: Riply 23.7.2008, 17:59 | ||
Сейчас, только переброшу это безобразие в пустой проект. Да, на всякий случай: я под Builder`ом. Все равно выкладывать ? |
| Автор: W4FhLF 23.7.2008, 18:01 |
Ну создай какой-нибудь тестовый проект, где в цикле скажем юзаешь эту функцию, скомпилируй и выложи. Я смогу точно сказать(надеюсь Но, Partizan, скорее всего прав. |
| Автор: Riply 23.7.2008, 18:04 |
Хорошо, только мне надо чуть времени. |
| Автор: DRUID3 23.7.2008, 18:05 | ||||
Ага... Причем, реально inline должен работать только с указателями на внешние объекты не имя собственных переменных и ничего не возвращая. Кто не совсем понимает почему пусть вспомнит какие функции компилятор делает inline по возможности без нашей просьбы.
очень похоже, на недавний спор "что лучше указатель или ссылка". То, что написали в учебнике для создания первичных представлений - одно. То что следует применять в отдельном случае на практике - другое. define - 100% разменяет объем на скорость. Директива inline, да еще не к месту примененная так и останется директивой. |
| Автор: Riply 23.7.2008, 18:56 | ||
"ничего не возвращая" в смысле не может быть и функцией в том числе ? P.S. Прикрепила файл. |
| Автор: DRUID3 23.7.2008, 19:03 | ||
void... а фнкцией она само собой быть не может. Это же подстановка. Вот как только появляется хоть один атрибут функции это уже не inline... |
| Автор: Riply 23.7.2008, 19:16 | ||
"Нда... Сказали мы с Петром Иванычем" (с) Либо у меня еще и в Delphi пробелы с образованием, либо C++ это совсем не Delphi Добавлено через 5 минут и 9 секунд P.S. А как насчет произведения, о котором я спрашивала в топике ? Всегда ли будет вычисляться левая часть ? |
| Автор: mes 23.7.2008, 20:48 | ||||
насколько я понял вопрос такой: всегда ли будет происходить присваивание? Да
т.е функция inline int max(int a, int b) { return (a>b)? a: b; } не будет инлайниться? не согласен |
| Автор: Alexeis 23.7.2008, 21:07 | ||
Мне тоже кажеться что должно работать. Возможно такое ограничение есть у одного из компиляторов. Насколько я помню есть ограничение на число машинных команд. |
| Автор: DRUID3 23.7.2008, 21:34 | ||||||||
Я не знаю Delphi, и не знаю что Вам на это сказать. Я имел ввиду, что нужно применить процедуры - ничего не возвращающие функции void fn_foo();
Крайний левый операнд в тринарном выражении будет вычисляться всегда - он проверяется на "0". Если он ">0" то второй оператор, а иначе - третий. Если же Вы хотите узнать будет ли повторяться бессмысленное умножение на "0" то да, будет.
А баба яга - протиФФ. Вообще что-бы понять затруднения компилера, сами подумайте, чем же отличается вызов функции от подстановки? Что собственно экономят? Время работы со стеком. Так когда с ним не надо работать??? Добавлено @ 21:38
Нет, реально ограничение на целесообразность подстановки. И ее "пик" это отсутствие собственных переменных и возврата. Хоть в C а хоть в C++. Работайте с полями глобальной структуры или делайте закрытые методы обращающиеся по указателю к полям объекта - будет вам счастье. А иначе мрак хаоса описанный в книжонке Саттера... |
| Автор: Torsten 23.7.2008, 23:01 | ||||||
Использовать define для этого точно не нужно, эта замена функции и в этом случае только усложнит сопровождение и отладку. Хотя бы вот такой код, уже приведет к неправельным действиям :
Использование inline - это лишь подсказка компилятору о том, что эту функцию стоит сделать inline, и совершенно не факт, что он это сделает.
Каким профайлером производились замеры ? |
| Автор: Riply 23.7.2008, 23:17 |
Не поняла, почему и что имеется ввиду под nLength+1 ? Может аLength+1 ? Это не страшно: изменим имя параметра. Меня больше волновало _Us_SetLength(pUnicodeString, pUnicodeString->Length + 1), но вроде все нормально. Да простым QueryPerformanceCounter - ом |
| Автор: Torsten 23.7.2008, 23:24 | ||
Лучше профайлером, тогда более менее точно станет понятно, на что именно больше всего тратится ресурсов.
Ну, тогда продолжайте использовать. Мое дело предупредить ^_^ |
| Автор: Alexeis 23.7.2008, 23:37 | ||
Дело не в имени, а в выражении. Насколько я знаю макрос может взять не все выражение, чтобы он взял все там нужно в выражении скобки поставить каждому параметру. |
| Автор: bilbobagginz 24.7.2008, 01:04 | ||||||||
с т.з. скорости ? думаю тот, который побыстрей. если критерий проверки - скорость. как тут ранее написали, читабельность чуток понижается, следовательно такой кусок стоит объяснить. но в принципе он ничего сложного не делает, поэтому такой кусок объяснять - время убивать зря.
множиться будет всегда, но можно сделать и быстрее, если не умножать, а делать побитовый & с нулём. поэтому, при условии, что длИны - представляются целыми типами, мой вариант таков:
_cbLen тут стоит запихать в скобочки, как сказал тов. Alexeis, но не обязательно. В данном конкретном случае это не страшно:
поведёт себя "хорошо", т.е х>y+z будет всегда идентично x>(y+z). НО, т.к. иногда действия с операндами, которые запихивают в макро дают нежелаемые результаты, не засовывать "операнды" макро в скобочки - плохой вкус. |
| Автор: Lazin 24.7.2008, 08:34 |
| не стоит использовать define, нервные клетки не восстанавливаются... Обычная функция делающая то-же самое будет не медленнее. Компилятор в состоянии разобраться, в каком контексте вызывается функция, если она вызывается один раз, то встраивание ничего не даст кроме увеличения объема кода. Если функция вызывается в цикле, то даст, и скорее всего она будет встроена. Так зачем брать на себя работу компилятора? |
| Автор: DRUID3 24.7.2008, 09:22 | ||
Это как???
Нет, он не всегда, причем далеко не всегда в состоянии разобраться... |
| Автор: Lazin 24.7.2008, 09:36 | ||
нет
с тем примером в 2 строчки он пожалуй сможет разобраться. вообще чем меньше функция, тем больше шансов что она будет заинлайнена, если функция большая и выполняется долго, то стоимость ее вызова, по сравнению с выполнением самой функциии незначительна и встраивать смысла нет... Но все эти аспекты анализировать самостоятельно - занятие неблагодарное, так что лучше доверить это компилятору. Плюс функции в том, что в одном случае она будет встроена, в другом нет. Если она вызывается из 100 разных мест, то реально встраивать нужно в одном - двух, там где она часто вызывается и стоимость вызова большая. В остальных случаях проще вызвать... Ну а макрос на 100% разменяет объем на скорость, при этом разницы в скорости не будет, так как там где нужно функция будет то-же встроена... |
| Автор: Alexeis 24.7.2008, 09:53 | ||
Вот выдержка из справки по билдеру
Ни каких ограничений на то что функция не может возвращать значения или создавать локальные переменные. Это могут быть только ограничения отдельно взятого хилого компилятора. |
| Автор: xvr 24.7.2008, 11:18 | ||||||||||||
Первый
Проверил - сделал вызовы обоих версих функции, скормил все это Intel компилятору (на Linux) - код АБСОЛЮТНО одинаковый! (см атач) Кроме того, у define'а есть еще один ОГРОМНЫЙ подводный камень:
|
| Автор: DRUID3 24.7.2008, 11:39 | ||
а как?
да, вобщем-то верно. За тем исключением, что "вобщем-то". Иногда нужно четко что-то встроить. И очень не хочется "балансировать" на грани встроенного в компилятор автомата, который решает - встраивать или нет. Ни каких ограничений на то что функция не может возвращать значения или создавать локальные переменные. Это могут быть только ограничения отдельно взятого хилого компилятора. Это перечислены пункты когда функция точно не станет inline. И не факт, что в остальных случаях станет. Неплохо бы все-таки вспомнить как будет работать функция и на чем попытается сэкономить компилер. Врать не буду с борландом йа не работаю и не намереваюсь. Очень возможно, что он, например, преобразует внутри себя локальные переменные в глобалные и работает с их адресами и т.д... Я же свои злоключения высказал, они могут пригодиЦЦо и другим идущим по этому пути. Вообще было бы очень клево, если бы кто-то не поленился, посидел с дизассемблером и несколькими компиляторами и накатал статейку "о том, как не надо применять inline" |
| Автор: Любитель 24.7.2008, 15:18 | ||||||
ЭТо кто вам такую ерунду сказал?1
Ничего подобного. 100% на всех компиляторах - инлайна никогда не будет. Есть всякие форсирующие директивы, есть ключевое слово inline - хинт компилеру, есть оптимизатор. Ничего подобного. Простые рекурсии (читай - рекурсии, которые были не в тему) - любой хороший комплер в состоянии развернуть. |
| Автор: Lazin 24.7.2008, 15:30 | ||||
а стек для чего?
вот xvr написал исчерпывающий пост, что еще нужно? сидеть с дизассемблером не нужно, достаточно в release версии программы поставить брэйкпоинт в место вызова функции, например в цикле и когда он сработает клацнуть Show Disassembly, бегая отладчиком по рилиз версии, очень хорошо видно что и когда оптимизатор встраивает даже без дизассемблера, так как отладчик в заинлайненые функции не заходит. |
| Автор: varnie 24.7.2008, 15:46 | ||
| Effective C++, Глава 1: Правило 1:
|
| Автор: DRUID3 24.7.2008, 16:40 | ||
Суровая правда жизни
А это тут то причем??? А подстановкой мы что экономим!!!??? угу... А еще надо хорошо учиться и слушать папу и маму... |
| Автор: Любитель 24.7.2008, 17:23 |
Пруфлинк? При том, что развернув рекурсию в цикл, полученное можно заинлайнить. |
| Автор: Любитель 24.7.2008, 17:43 | ||||
| Насчёт рекурсии - проверено на VC++ 2005, на VC++ 2008 тоже, думаю, сработает. Исходный код:
Получаем:
|
| Автор: varnie 24.7.2008, 18:20 | ||
я написал это не для того, чтобы пустые фразы ниже увидеть, а к тому, что если кому-то это интересно, то как минимум можно обратиться к материалу из книги, которую я указал для уточнения. |
| Автор: Lazin 24.7.2008, 18:25 | ||
какой подстановкой? ты о чем? локальные переменные размещаются в стеке, всегда... встроена функция, или нет, это не важно |
| Автор: phprus 24.7.2008, 19:53 | ||
C++ компилятор от борланда на столько крив и глючен, что не достоен называться компилятором.Он отстал от жизни лет на 20. Возьмите как образец G++, компилятор от Intel или M$ VS. Хвостовая рекурсия раскладывается в цикл элементарно. Такие оптимизации уже давно не редкость. Это именно что ерунда. Сколько пользовался !нормальными! компиляторами никогда такого не замечал в релиз-сборках проектов. Как я понимаю имеется ввиду inline-подстановка тела функции? Если я прав, то в сад. Подстановкой мы экономим вызов функции, те переход на удаленный участок кода, которого скорее всего нет в кеше процессора и тд... А память в стеке выделяется мгновенно, ибо это всего-лишь изменение значения указателя на вершину стека и ВСЕ. Кроме того стек почти гарантированно лежит в кэше процессора, а это еще ускорит работу с используемой частью стека. |
| Автор: Riply 25.7.2008, 07:34 |
| "Ох, не легкая это работа - из болота тащить бегемота" (с) Спасибо всем тащившим P.S. Я много вынесла из этой ветки. |
| Автор: W4FhLF 26.7.2008, 14:34 |
| Хоть уже и не актуально, но раз уж обещал дизассемблировать примеры, то в выложенном на первой странице exe компилятор действительно проигнорировал inline, на уровне маш. кода осуществялется вызов отдельной процедуры. Извиняюсь за задержку, запамятовал |
| Автор: Riply 26.7.2008, 22:38 | ||
"не актуально" становится только тогда, когда участники и автор топика полностью разобрались в данном воросе и "постигли сущность сущностей " Не знаю как другие, но я до этого состояния в данной теме еще не дошла Даже не посмотрела что за "мрак хаоса описанный в книжонке Саттера..." (с) DRUID3
Спасибо большое. Теперь предположения, превратились в уверенность |
| Автор: Supersedes 29.7.2008, 12:26 |
| Riply, а с каким компилятором ты вообще работаешь? |
| Автор: Riply 29.7.2008, 19:43 |
В данном случае, все происходило под Builder`ом. |
| Автор: xvr 29.7.2008, 22:41 | ||||||||
Кстати, о птичках - откомпилировал тест под Билдером (6.0)
|
| Автор: Riply 30.7.2008, 02:27 |
Можете себе представить какое мнение у меня сложилось о способностях Builder`а, после того как он отказался инлайнить такую простую функцию. Вам удалось чуть-чуть его (это мнение) поднять . Builder должен быть Вам благодарен P.S. И я тоже благодарна |