Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > inline и define - выбор


Автор: Riply 23.7.2008, 17:23
Здравствуйте !
Допустим, у нас есть такая функция, которую мы собираемся вызывать 
так много раз, что и не сосчитаешь smile
Код

__inline NTSTATUS Us_SetLength(const PUNICODE_STRING pUs, const ULONG aLength)
{
  if (pUs->MaximumLength >= aLength)
   {
     pUs->Length = aLength;
     return STATUS_SUCCESS;
   };
  return STATUS_NAME_TOO_LONG;
};

Пробуем написать ее аналог, используя "дефайны"
Код

#define _Us_SetLength(_pus, _cbLen) ((_pus)->MaximumLength >= _cbLen) ?    \
((_pus)->Length = _cbLen) * 0 : STATUS_NAME_TOO_LONG


Какой из этих двух вариантов (если конечно они не содержат ошибок) предпочтительней для использования ?
(первый в три раза медленнее второго, но второй как-то ненадежно выглядит smile)
Например, в нем используется выражение " ((_pus)->Length = _cbLen) * 0 "
Всегда ли его левый сомножитель будет "вычисляться" или, при некоторых условиях, может игнорироваться ?

Автор: Alexeis 23.7.2008, 17:31
Цитата(Riply @  23.7.2008,  16:23 Найти цитируемый пост)
первый в три раза медленнее второго, но второй как-то ненадежно выглядит

  Мож под дебагом игнорируется директива __inline. 
  __inline однозначно предпочтительнее, так как там идет проверка типов на этапе компиляции и проч. Нужно попробовать дизассемблировать релизовый экзешник и сравнить код. Я думаю разницы не будет.

Автор: Riply 23.7.2008, 17:38
Цитата(Alexeis @  23.7.2008,  17:31 Найти цитируемый пост)
Мож под дебагом игнорируется директива __inline. 
  __inline однозначно предпочтительнее, так как там идет проверка типов на этапе компиляции и проч. Нужно попробовать дизассемблировать релизовый экзешник и сравнить код. Я думаю разницы не будет. 


Попробовала запустить не из под среды.
Результат тот же: соотношение один к трем.
Сейчас попробую посмотреть в CPU-шке, правда я там себя не очень уверенно чувствую smile

Автор: W4FhLF 23.7.2008, 17:49
Выложи два варианта в виде exe в релиз сборке. Посмотрим на оптимизацию. 

Автор: Partizan 23.7.2008, 17:58
ммм...насколько я знаю компилятор оставляет за собой право не инлайнить функцию по своему усмотрению даже тогда когда явно указан модификатор __inline...

Автор: Riply 23.7.2008, 17:59
Цитата(W4FhLF @  23.7.2008,  17:49 Найти цитируемый пост)
Выложи два варианта в виде exe в релиз сборке. Посмотрим на оптимизацию.


Сейчас, только переброшу это безобразие в пустой проект.
Да, на всякий случай: я под Builder`ом. Все равно выкладывать ?

Автор: W4FhLF 23.7.2008, 18:01
Цитата(Riply @  23.7.2008,  17:59 Найти цитируемый пост)
Да, на всякий случай: я под Builder`ом. Все равно выкладывать ?


Ну создай какой-нибудь тестовый проект, где в цикле скажем юзаешь эту функцию, скомпилируй и выложи. Я смогу точно сказать(надеюсьsmile ) почему одно работает медленнее в три раза другого. 

Но, Partizan, скорее всего прав. 

Автор: Riply 23.7.2008, 18:04
Цитата(W4FhLF @  23.7.2008,  18:01 Найти цитируемый пост)
Ну создай какой-нибудь тестовый проект


Хорошо, только мне надо чуть времени.

Автор: DRUID3 23.7.2008, 18:05
Цитата(Partizan @  23.7.2008,  16:58 Найти цитируемый пост)
ммм...насколько я знаю компилятор оставляет за собой право не инлайнить функцию по своему усмотрению даже тогда когда явно указан модификатор __inline... 

Ага... Причем, реально inline должен работать только с указателями на внешние объекты не имя собственных переменных и ничего не возвращая. Кто не совсем понимает почему пусть вспомнит какие функции компилятор делает inline по возможности без нашей просьбы. 

Цитата(Alexeis @  23.7.2008,  16:31 Найти цитируемый пост)

  __inline однозначно предпочтительнее, так как там идет проверка типов на этапе компиляции и проч. Нужно попробовать дизассемблировать релизовый экзешник и сравнить код. Я думаю разницы не будет. 

очень похоже, на недавний спор "что лучше указатель или ссылка". То, что написали в учебнике для создания первичных представлений - одно. То что следует применять в отдельном случае на практике - другое. define - 100% разменяет объем на скорость. Директива inline, да еще не к месту примененная так и останется директивой.

Автор: Riply 23.7.2008, 18:56
Цитата(DRUID3 @  23.7.2008,  18:05 Найти цитируемый пост)
Ага... Причем, реально inline должен работать только с указателями на внешние объекты не имя собственных переменных и ничего не возвращая. 


"ничего не возвращая" в смысле не может быть и функцией в том числе ?

P.S.
 Прикрепила файл.

Автор: DRUID3 23.7.2008, 19:03
Цитата(Riply @  23.7.2008,  17:56 Найти цитируемый пост)
"ничего не возвращая" в смысле не может быть и функцией в том числе ?

void... а фнкцией она само собой быть не может. Это же подстановка. Вот как только появляется хоть один атрибут функции это уже не inline... 

Автор: Riply 23.7.2008, 19:16
Цитата(DRUID3 @  23.7.2008,  19:03 Найти цитируемый пост)
void... а фнкцией она само собой быть не может. Это же подстановка. Вот как только появляется хоть один атрибут функции это уже не inline...  


"Нда... Сказали мы с Петром Иванычем" (с) smile

Либо у меня еще и в Delphi пробелы с образованием, либо C++ это совсем не Delphi  smile

Добавлено через 5 минут и 9 секунд
P.S.
 А как насчет произведения, о котором я спрашивала в топике ?
 Всегда ли будет вычисляться левая часть ?

Автор: mes 23.7.2008, 20:48
Цитата(Riply @  23.7.2008,  17:23 Найти цитируемый пост)
Например, в нем используется выражение " ((_pus)->Length = _cbLen) * 0 "
Всегда ли его левый сомножитель будет "вычисляться" или, при некоторых условиях, может игнорироваться ?

насколько я понял вопрос такой: всегда ли будет происходить присваивание?  Да


Цитата(DRUID3 @  23.7.2008,  19:03 Найти цитируемый пост)
void... а фнкцией она само собой быть не может. Это же подстановка. Вот как только появляется хоть один атрибут функции это уже не inline...  


т.е функция  inline int max(int a, int b) { return (a>b)?  a: b; } не будет инлайниться? не согласен 


Автор: Alexeis 23.7.2008, 21:07
Цитата(mes @  23.7.2008,  19:48 Найти цитируемый пост)
т.е функция  inline int max(int a, int b) { return (a>b)?  a: b; } не будет инлайниться? не согласен 

  Мне тоже кажеться что должно работать. Возможно такое ограничение есть у одного из компиляторов. Насколько я помню есть ограничение на число машинных команд.

Автор: DRUID3 23.7.2008, 21:34
Цитата(Riply @  23.7.2008,  18:16 Найти цитируемый пост)
Либо у меня еще и в Delphi пробелы с образованием, либо C++ это совсем не Delphi 

Я не знаю Delphi, и не знаю что Вам на это сказать. Я имел ввиду, что нужно применить процедуры - ничего не возвращающие функции 
void fn_foo();
Цитата(Riply @  23.7.2008,  18:16 Найти цитируемый пост)
 А как насчет произведения, о котором я спрашивала в топике ?
 Всегда ли будет вычисляться левая часть ? 

Крайний левый операнд в тринарном выражении будет вычисляться всегда - он проверяется на "0". Если он ">0" то второй оператор, а иначе - третий. Если же Вы хотите узнать будет ли повторяться бессмысленное умножение на "0" то да, будет.

Цитата(mes @  23.7.2008,  19:48 Найти цитируемый пост)
т.е функция  inline int max(int a, int b) { return (a>b)?  a: b; } не будет инлайниться? не согласен 

А баба яга - протиФФ. smile  Я рассказал когда inline будет 100% inline во всех компиляторах. Некоторые случаи возможны и в более сложных ситуациях. Зависит от "ума" компилятора, и того к чему он преобразует внутри "себя любимого". Но, например, вообще нереализуем рекурсивный inline вызов. Столкнулся пару месяцев назад - чужой проект был "глубоко оптимизирован" - перед каждой функцией стояло inline. Я с ним долбался долго, а потом дай-ка думаю посношу это... и... и нифига не изменилось, блин! Поспрашивал на electronix? там сказали почитай Саттера. Почитал - полный бред ниочем, мол может оптимизировать? а может и не оптимизировать, смотря от урожая травы в Африке smile . И я блин вспомнил, читал де, что собственные закрытые функции класса компилер сам делает inline если они работают только с полями класса. Блин... Пришлось немного пошаманить, зато inline стали настоящими подстановками.

Вообще что-бы понять затруднения компилера, сами подумайте, чем же отличается вызов функции от подстановки? Что собственно экономят? Время работы со стеком. Так когда с ним не надо работать???

Добавлено @ 21:38
Цитата(Alexeis @  23.7.2008,  20:07 Найти цитируемый пост)
Мне тоже кажеться что должно работать. Возможно такое ограничение есть у одного из компиляторов. Насколько я помню есть ограничение на число машинных команд. 

Нет, реально ограничение на целесообразность подстановки. И ее "пик" это отсутствие собственных переменных и возврата. Хоть в C а хоть в C++. Работайте с полями глобальной структуры или делайте закрытые методы обращающиеся по указателю к полям объекта - будет вам счастье. А иначе мрак хаоса описанный в книжонке Саттера...

Автор: Torsten 23.7.2008, 23:01
Цитата(Riply @  23.7.2008,  17:23 Найти цитируемый пост)
Какой из этих двух вариантов (если конечно они не содержат ошибок) предпочтительней для использования ?

Использовать define для этого точно не нужно, эта замена функции и в этом случае только усложнит сопровождение и отладку.
Хотя бы вот такой код, уже приведет к неправельным действиям :
Код

_Us_SetLength(pUnicodeString, nLength+1)


Использование inline - это лишь подсказка компилятору о том, что эту функцию стоит сделать inline, и совершенно не факт, что он это сделает.


Цитата(Riply @  23.7.2008,  17:23 Найти цитируемый пост)
(первый в три раза медленнее второго, но второй как-то ненадежно выглядит )

Каким профайлером производились замеры ?

Автор: Riply 23.7.2008, 23:17
Цитата(Torsten @  23.7.2008,  23:01 Найти цитируемый пост)
Хотя бы вот такой код, уже приведет к неправельным действиям :


Не поняла, почему и что имеется ввиду под nLength+1 ? Может аLength+1 ?
Это не страшно: изменим имя параметра.  smile 
Меня больше волновало _Us_SetLength(pUnicodeString, pUnicodeString->Length + 1),
но вроде все нормально. 



Цитата(Torsten @  23.7.2008,  23:01 Найти цитируемый пост)
Каким профайлером производились замеры ?


Да простым QueryPerformanceCounter - ом

Автор: Torsten 23.7.2008, 23:24
Цитата(Riply @  23.7.2008,  23:17 Найти цитируемый пост)
Да простым QueryPerformanceCounter - ом

Лучше профайлером, тогда более менее точно станет понятно, на что именно больше всего тратится ресурсов.


Цитата(Riply @  23.7.2008,  23:17 Найти цитируемый пост)
Не поняла, почему и что имеется ввиду под nLength+1 ? Может аLength+1 ?Это не страшно: изменим имя параметра.   Меня больше волновало _Us_SetLength(pUnicodeString, pUnicodeString->Length + 1),но вроде все нормально. 

Ну, тогда продолжайте использовать. Мое дело предупредить ^_^

Автор: Alexeis 23.7.2008, 23:37
Цитата(Riply @  23.7.2008,  22:17 Найти цитируемый пост)
Не поняла, почему и что имеется ввиду под nLength+1 ? Может аLength+1 ?
Это не страшно: изменим имя параметра. 

  Дело не в имени, а в выражении. Насколько я знаю макрос может взять не все выражение, чтобы он взял все там нужно в выражении скобки поставить каждому параметру.

Автор: bilbobagginz 24.7.2008, 01:04
Цитата(Riply @  23.7.2008,  17:23 Найти цитируемый пост)
Какой из этих двух вариантов (если конечно они не содержат ошибок) предпочтительней для использования ?
(первый в три раза медленнее второго, но второй как-то ненадежно выглядит smile)

с т.з. скорости ?
думаю тот, который побыстрей.
если критерий проверки - скорость.
как тут ранее написали, читабельность чуток понижается, 
следовательно такой кусок стоит объяснить.
но в принципе он ничего сложного не делает, поэтому такой кусок объяснять - время убивать зря.
Цитата(Riply @  23.7.2008,  17:23 Найти цитируемый пост)

Например, в нем используется выражение " ((_pus)->Length = _cbLen) * 0 "
Всегда ли его левый сомножитель будет "вычисляться" или, при некоторых условиях, может игнорироваться ?

множиться будет всегда, но можно сделать и быстрее, если не умножать, а делать побитовый & с нулём.
поэтому,  при условии, что длИны - представляются целыми типами,  мой вариант таков:
Код

#define _Us_SetLength(_pus, _cbLen) (((_pus)->MaximumLength >= (_cbLen)) ? \
                                     (((_pus)->Length = (_cbLen)) & 0) : \
                                     STATUS_NAME_TOO_LONG)

_cbLen тут стоит запихать в скобочки, как сказал тов. Alexeis, но не обязательно.
В данном конкретном случае это не страшно: 
  • сравнение вычисляется слева-направо
  • сравнение имеет более низкий приоритет, чем сложение.
т.е. в предложенном случае, ваше оригинальное макро:
Код

_Us_SetLength(_pus,_cbLen+1)

поведёт себя "хорошо", т.е х>y+z будет всегда идентично x>(y+z). 
НО, т.к. иногда действия с операндами, которые запихивают в макро дают нежелаемые результаты,  не засовывать "операнды" макро в скобочки - плохой вкус.

Автор: Lazin 24.7.2008, 08:34
не стоит использовать define, нервные клетки не восстанавливаются...
Обычная функция делающая то-же самое будет не медленнее.
Компилятор в состоянии разобраться, в каком контексте вызывается функция, если она вызывается один раз, то встраивание ничего не даст кроме увеличения объема кода.
Если функция вызывается в цикле, то даст, и скорее всего она будет встроена. Так зачем брать на себя работу компилятора?

Автор: DRUID3 24.7.2008, 09:22
Цитата(Lazin @  24.7.2008,  07:34 Найти цитируемый пост)
Обычная функция делающая то-же самое будет не медленнее.

Это как???  smile "На глазок"?

Цитата(Lazin @  24.7.2008,  07:34 Найти цитируемый пост)
Компилятор в состоянии разобраться, в каком контексте вызывается функция, если она вызывается один раз, то встраивание ничего не даст кроме увеличения объема кода.
Если функция вызывается в цикле, то даст, и скорее всего она будет встроена. Так зачем брать на себя работу компилятора? 

 Нет, он не всегда, причем далеко не всегда в состоянии разобраться...

Автор: Lazin 24.7.2008, 09:36
Цитата(DRUID3 @  24.7.2008,  09:22 Найти цитируемый пост)
Это как???  smile "На глазок"?

нет smile 

Цитата(DRUID3 @  24.7.2008,  09:22 Найти цитируемый пост)
Нет, он не всегда, причем далеко не всегда в состоянии разобраться... 

с тем примером в 2 строчки он пожалуй сможет разобраться.
вообще чем меньше функция, тем больше шансов что она будет заинлайнена, если функция большая и выполняется долго, то стоимость ее вызова, по сравнению с выполнением самой функциии незначительна и встраивать смысла нет...
Но все эти аспекты анализировать самостоятельно - занятие неблагодарное, так что лучше доверить это компилятору.
Плюс функции в том, что в одном случае она будет встроена, в другом нет. Если она вызывается из 100 разных мест, то реально встраивать нужно в одном - двух, там где она часто вызывается и стоимость вызова большая. В остальных случаях проще вызвать... Ну а макрос на 100% разменяет объем на скорость, при этом разницы в скорости не будет, так как там где нужно функция будет то-же встроена...

Автор: Alexeis 24.7.2008, 09:53
Вот выдержка из справки по билдеру
Цитата

The compiler cannot inline a function if: 


  • The function or its caller is compiled with /Ob0 (the default option for debug builds). 
  • The function and the caller use different types of exception handling (C++ exception handling in one, structured exception handling in the other). 
  • The function has a variable argument list.
  • The function uses inline assembly, unless compiled with /Og, /Ox, /O1, or /O2.
  • The function is recursive and not accompanied by #pragma inline_recursion(on). With the pragma, recursive functions are inlined to a default depth of 16 calls. To reduce the inlining depth, use inline_depth pragma.
  • The function is virtual and is called virtually. Direct calls to virtual functions can be inlined.
  • The program takes the address of the function and the call is made via the pointer to the function. Direct calls to functions that have had their address taken can be inlined.
  • The function is also marked with the naked __declspec modifier.




Ни каких ограничений на то что функция не может возвращать значения или создавать локальные переменные. Это могут быть только ограничения отдельно взятого хилого компилятора.

Автор: xvr 24.7.2008, 11:18
Цитата(Riply @ 23.7.2008,  17:23)
Здравствуйте !
Допустим, у нас есть такая функция, которую мы собираемся вызывать 
так много раз, что и не сосчитаешь smile
Код

__inline NTSTATUS Us_SetLength(const PUNICODE_STRING pUs, const ULONG aLength)
{
  if (pUs->MaximumLength >= aLength)
   {
     pUs->Length = aLength;
     return STATUS_SUCCESS;
   };
  return STATUS_NAME_TOO_LONG;
};

Пробуем написать ее аналог, используя "дефайны"
Код

#define _Us_SetLength(_pus, _cbLen) ((_pus)->MaximumLength >= _cbLen) ?    \
((_pus)->Length = _cbLen) * 0 : STATUS_NAME_TOO_LONG


Какой из этих двух вариантов (если конечно они не содержат ошибок) предпочтительней для использования ?

Первый
Цитата

(первый в три раза медленнее второго, но второй как-то ненадежно выглядит smile)
Нормальный компилятор должен сделать не медленнее
Цитата

Например, в нем используется выражение " ((_pus)->Length = _cbLen) * 0 "
Всегда ли его левый сомножитель будет "вычисляться" или, при некоторых условиях, может игнорироваться ?
Рекомендую заменить это 'выражение' на (((_pus)->Length = (_cbLen)) , 0) Хотя нормальный компилятор сделает практически тоже самое

Проверил - сделал вызовы обоих версих функции, скормил все это Intel компилятору (на Linux) - код АБСОЛЮТНО одинаковый! (см атач)

Кроме того, у define'а есть еще один ОГРОМНЫЙ подводный камень:
Код

// Somewhere in .h was defined:
__inline NTSTATUS Us_SetLength(const PUNICODE_STRING pUs, const ULONG aLength)
{...}

// Somewhere in .cpp is -
int Us_SetLength(MyStruct* pUs, int mylen)
{...}
Это нормально откомпилится и будет работать (С++ допускает функции с одинаковыми именами но разными параметрами). Если бы у вас был #define вместо первой функции - вы получили бы маловразумительные сообщения о массе ошибок на месте определения второй функции.

Автор: DRUID3 24.7.2008, 11:39
Цитата(Lazin @  24.7.2008,  08:36 Найти цитируемый пост)
нет

а как?
Цитата(Lazin @  24.7.2008,  08:36 Найти цитируемый пост)
с тем примером в 2 строчки он пожалуй сможет разобраться.
вообще чем меньше функция, тем больше шансов что она будет заинлайнена, если функция большая и выполняется долго, то стоимость ее вызова, по сравнению с выполнением самой функциии незначительна и встраивать смысла нет...
Но все эти аспекты анализировать самостоятельно - занятие неблагодарное, так что лучше доверить это компилятору.
Плюс функции в том, что в одном случае она будет встроена, в другом нет. Если она вызывается из 100 разных мест, то реально встраивать нужно в одном - двух, там где она часто вызывается и стоимость вызова большая. В остальных случаях проще вызвать... Ну а макрос на 100% разменяет объем на скорость, при этом разницы в скорости не будет, так как там где нужно функция будет то-же встроена... 

да, вобщем-то верно. За тем исключением, что "вобщем-то". Иногда нужно четко что-то встроить. И очень не хочется "балансировать" на грани встроенного в компилятор автомата, который решает - встраивать или нет. 

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

Я же свои злоключения высказал, они могут пригодиЦЦо и другим идущим по этому пути.  smile 

Вообще было бы очень клево, если бы кто-то не поленился, посидел с дизассемблером и несколькими компиляторами и накатал статейку "о том, как не надо применять inline"  smile 

Автор: Любитель 24.7.2008, 15:18
Цитата(DRUID3 @  23.7.2008,  18:05 Найти цитируемый пост)
Ага... Причем, реально inline должен работать только с указателями на внешние объекты не имя собственных переменных и ничего не возвращая. Кто не совсем понимает почему пусть вспомнит какие функции компилятор делает inline по возможности без нашей просьбы. 

Цитата(DRUID3 @  23.7.2008,  19:03 Найти цитируемый пост)
void... а фнкцией она само собой быть не может. Это же подстановка. Вот как только появляется хоть один атрибут функции это уже не inline

ЭТо кто вам такую ерунду сказал?1 smile 

Цитата(DRUID3 @  23.7.2008,  21:34 Найти цитируемый пост)
Я рассказал когда inline будет 100% inline во всех компиляторах. Некоторые случаи возможны и в более сложных ситуациях. 

Ничего подобного. 100% на всех компиляторах - инлайна никогда не будет. Есть всякие форсирующие директивы, есть ключевое слово inline - хинт компилеру, есть оптимизатор.

Цитата(DRUID3 @  23.7.2008,  21:34 Найти цитируемый пост)
Но, например, вообще нереализуем рекурсивный inline вызов.

Ничего подобного. Простые рекурсии (читай - рекурсии, которые были не в тему) - любой хороший комплер в состоянии развернуть.

Автор: Lazin 24.7.2008, 15:30
Цитата(DRUID3 @  24.7.2008,  11:39 Найти цитируемый пост)
Врать не буду с борландом йа не работаю и не намереваюсь. Очень возможно, что он, например, преобразует внутри себя локальные переменные в глобалные и работает с их адресами и т.д...

а стек для чего?

Цитата(DRUID3 @  24.7.2008,  11:39 Найти цитируемый пост)
Вообще было бы очень клево, если бы кто-то не поленился, посидел с дизассемблером и несколькими компиляторами и накатал статейку "о том, как не надо применять inline"

вот xvr написал исчерпывающий пост, что еще нужно?
сидеть с дизассемблером не нужно, достаточно в release версии программы поставить брэйкпоинт в место вызова функции, например в цикле и когда он сработает клацнуть Show Disassembly, бегая отладчиком по рилиз версии, очень хорошо видно что и когда оптимизатор встраивает даже без дизассемблера, так как отладчик в заинлайненые функции не заходит. 

Автор: varnie 24.7.2008, 15:46
Effective C++, Глава 1:
Правило 1:
Цитата

предпочитайте const и inline использованию #define

Автор: DRUID3 24.7.2008, 16:40
Цитата(Любитель @  24.7.2008,  14:18 Найти цитируемый пост)
ЭТо кто вам такую ерунду сказал?

Суровая правда жизни smile ...
Цитата(Любитель @  24.7.2008,  14:18 Найти цитируемый пост)
Ничего подобного. Простые рекурсии (читай - рекурсии, которые были не в тему) - любой хороший комплер в состоянии развернуть. 

А это тут то причем???  smile вон, смотрите, даже борланд по определению не сделает inline рекурсивную функцию. Отекда у нас уже пошла речь о разложении простой рекурсии?
Цитата(Lazin @  24.7.2008,  14:30 Найти цитируемый пост)
а стек для чего?

А подстановкой мы что экономим!!!??? smile 
Цитата(varnie @  24.7.2008,  14:46 Найти цитируемый пост)
предпочитайте const и inline использованию #define

угу... А еще надо хорошо учиться и слушать папу и маму... smile 

Автор: Любитель 24.7.2008, 17:23
Цитата(DRUID3 @  24.7.2008,  16:40 Найти цитируемый пост)
Суровая правда жизни

Пруфлинк?

Цитата(DRUID3 @  24.7.2008,  16:40 Найти цитируемый пост)
даже борланд 

 smile

Цитата(DRUID3 @  24.7.2008,  16:40 Найти цитируемый пост)
А это тут то причем???  

При том, что развернув рекурсию в цикл, полученное можно заинлайнить.

Автор: Любитель 24.7.2008, 17:43
Насчёт рекурсии - проверено на VC++ 2005, на VC++ 2008 тоже, думаю, сработает.

Исходный код:
Код

#include <stdio.h>

#pragma inline_recursion(on)

int __forceinline add(int a, int b)
{
    if (b == 0)
        return a;
    else
        return add(1 + a, b - 1);
}

int main()
{
    printf("%i", add(5, 7));
}


Получаем:
Код

push        0Ch     ; типа фтопку нашу функцию :)
push        offset string "%i"
call           dword ptr [__imp__printf ] 
add          esp,8 
xor           eax,eax 
ret     

Автор: varnie 24.7.2008, 18:20
Цитата(varnie)

предпочитайте const и inline использованию #define

Цитата(DRUID3 @  24.7.2008,  19:40 Найти цитируемый пост)

угу... А еще надо хорошо учиться и слушать папу и маму... smile  

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

Автор: Lazin 24.7.2008, 18:25
Цитата(DRUID3 @ 24.7.2008,  16:40)
Цитата(Lazin @  24.7.2008,  14:30 Найти цитируемый пост)
а стек для чего?

А подстановкой мы что экономим!!!??? smile 

какой подстановкой? ты о чем?
локальные переменные размещаются в стеке, всегда... встроена функция, или нет, это не важно

Автор: phprus 24.7.2008, 19:53
Цитата(DRUID3 @  24.7.2008,  16:40 Найти цитируемый пост)
вон, смотрите, даже борланд по определению не сделает inline рекурсивную функцию.

C++ компилятор от борланда на столько крив и глючен, что не достоен называться компилятором.Он отстал от жизни лет на 20.
Возьмите как образец G++, компилятор от Intel или M$ VS.


Цитата(DRUID3 @  24.7.2008,  16:40 Найти цитируемый пост)
Отекда у нас уже пошла речь о разложении простой рекурсии?

Хвостовая рекурсия раскладывается в цикл элементарно. Такие оптимизации уже давно не редкость.

Цитата(DRUID3 @  24.7.2008,  16:40 Найти цитируемый пост)
Суровая правда жизни smile ...

Это именно что ерунда. Сколько пользовался !нормальными! компиляторами никогда такого не замечал в релиз-сборках проектов.

Цитата(DRUID3 @  24.7.2008,  16:40 Найти цитируемый пост)
А подстановкой мы что экономим!!!??? smile 

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

Автор: Riply 25.7.2008, 07:34
"Ох, не легкая это работа - из болота тащить бегемота" (с) 
Спасибо всем тащившим  smile

P.S.
 Я много вынесла из этой ветки. 

Автор: W4FhLF 26.7.2008, 14:34
Хоть уже и не актуально, но раз уж обещал дизассемблировать примеры, то в выложенном на первой странице exe компилятор действительно проигнорировал inline, на уровне маш. кода осуществялется вызов отдельной процедуры. 

Извиняюсь за задержку, запамятовал smile 

Автор: Riply 26.7.2008, 22:38
Цитата(W4FhLF @  26.7.2008,  14:34 Найти цитируемый пост)
Хоть уже и не актуально


"не актуально" становится только тогда, когда участники и автор топика
полностью разобрались в данном воросе и "постигли сущность сущностей " smile
Не знаю как другие, но я до этого состояния в данной теме еще не дошла
Даже не посмотрела что за "мрак хаоса описанный в книжонке Саттера..."  (с) DRUID3
smile

Цитата(W4FhLF @  26.7.2008,  14:34 Найти цитируемый пост)
но раз уж обещал дизассемблировать примеры, то в выложенном на первой странице exe компилятор действительно проигнорировал inline, на уровне маш. кода осуществялется вызов отдельной процедуры


Спасибо большое. Теперь предположения, превратились в уверенность smile


Автор: Supersedes 29.7.2008, 12:26
Riply, а с каким компилятором ты вообще работаешь?

Автор: Riply 29.7.2008, 19:43
Цитата(Supersedes @  29.7.2008,  12:26 Найти цитируемый пост)
Riply, а с каким компилятором ты вообще работаешь?


В данном случае, все происходило под Builder`ом.

Автор: xvr 29.7.2008, 22:41
Цитата(Riply @ 29.7.2008,  19:43)
Цитата(Supersedes @  29.7.2008,  12:26 Найти цитируемый пост)
Riply, а с каким компилятором ты вообще работаешь?


В данном случае, все происходило под Builder`ом.

Кстати, о птичках - откомпилировал тест под Билдером (6.0)
Код

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>

struct UNICODE_STRING {
 ULONG MaximumLength;
 ULONG Length;
};

//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
private:    // User declarations
 int v;
 UNICODE_STRING us;
public:        // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif


Код

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

__inline int Us_SetLength(UNICODE_STRING* pUs, const ULONG aLength)
{
  if (pUs->MaximumLength >= aLength)
   {
     pUs->Length = aLength;
     return 0;
   };
  return 1;
};

__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 v=Us_SetLength(&us,10);
}
//---------------------------------------------------------------------------
Поставил режим 'Release', все заинлайнилось:

Код

 ;    
 ;    {
 ;     v=Us_SetLength(&us,10);
 ;    
?live16385@32: ; EBX = $delflag
    mov eax,dword ptr [ebp-4]
    add eax,756
    cmp dword ptr [eax],10
    jb        short @3
    mov dword ptr [eax+4],10
    xor edx,edx
    jmp short @4
@3:
    mov edx,1
@4:
    mov eax,dword ptr [ebp-4]
    mov dword ptr [eax+752],edx
 ;    
 ;    }
Вывод - хотите производительности, включайте оптимизации и будет вам счастье  smile 

Автор: Riply 30.7.2008, 02:27
Цитата(xvr @  29.7.2008,  22:41 Найти цитируемый пост)
Поставил режим 'Release', все заинлайнилось


Можете себе представить какое мнение у меня сложилось о способностях Builder`а,
после того как он отказался инлайнить такую простую функцию.
Вам удалось чуть-чуть его (это мнение) поднять . Builder должен быть Вам благодарен smile
P.S.
 И я тоже благодарна smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)