关于inline的疑惑,请教高手,万分感谢

yyzz1029 2009-06-11 06:26:38
编译的时候内联函数可以直接被嵌入到目标代码中,什么情况下可以生效
如果我这样写
#include "stdafx.h"


int inline add(int i)
{
i++;
return i;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a=2;
add(a);
cout<<a<<endl;
return 0;
}

这个时候内联函数生效了吗?我觉得还是进行了函数调用了啊。
...全文
224 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
yyzz1029 2009-06-18
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 superbtl 的回复:]
#include "stdafx.h"


int inline add(int i)
{
i++;
return i;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a=2;
a = add(a); //注意了 或者 调用引用或者指针
cout < <a < <endl;
return 0;
}
这个问题不是处在内联函数上,你这个是C++基本语法不对吧
楼上怎么都直接找内联函数麻烦啊
[/Quote]


不明白a = add(a); //注意了 或者 调用引用或者指针
为什么要调用引用或者指针啊?
wlwshang 2009-06-18
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 wlwshang 的回复:]
引用楼主 yyzz1029 的帖子:
编译的时候内联函数可以直接被嵌入到目标代码中,什么情况下可以生效
如果我这样写
#include "stdafx.h"


int inline add(int i)//这里inline应该提前到int
{
i++;
return i; //returnning local vaeiable is not good
}
int _tmain(int argc, _TCHAR* argv[])
{
int a=2;
add(a);//在这里会展开inline function.
cout < <a < <endl;
return 0;
}

这个时候内联函数生效了吗?我觉得还是进行…
[/Quote]
wlwshang 2009-06-18
  • 打赏
  • 举报
回复
[Quote=引用楼主 yyzz1029 的帖子:]
编译的时候内联函数可以直接被嵌入到目标代码中,什么情况下可以生效
如果我这样写
#include "stdafx.h"


int inline add(int i)
{
i++;
return i; //returnning local vaeiable is not good
}
int _tmain(int argc, _TCHAR* argv[])
{
int a=2;
add(a);//在这里会展开inline function.
cout < <a < <endl;
return 0;
}

这个时候内联函数生效了吗?我觉得还是进行了函数调用了啊。
[/Quote]
hz_yck 2009-06-18
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 hikaliv 的回复:]
引用 4 楼 Loaden 的回复:
最近在考虑函数速度的优化问题。一般函数分为普通函数和inline函数,因为既然inline是编译器展开,那么我何不手动展开试试呢。在频繁访问数据的情况下,他们各自的速度对比是怎样的?
通常情况,inline比普通调用要快,但是,如果我是通过对象A调用访问对象B的数据呢?普通函数相对inline真的慢?inline手动展开了,要好几次访问B,然后再访问数据;而普通的调用,只需要访问一次B的调用;手动展…
[/Quote]

有些代码不是高级语言写得出来的
hz_yck 2009-06-18
  • 打赏
  • 举报
回复
递归内联展不开,除非递归能先被优化成循环,否则不知道展开的深度
superbtl 2009-06-15
  • 打赏
  • 举报
回复
#include "stdafx.h"


int inline add(int i)
{
i++;
return i;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a=2;
a = add(a); //注意了 或者 调用引用或者指针
cout < <a < <endl;
return 0;
}
这个问题不是处在内联函数上,你这个是C++基本语法不对吧
楼上怎么都直接找内联函数麻烦啊
Jalien 2009-06-15
  • 打赏
  • 举报
回复
很好很强大!没有试过。。。 先mark[Quote=引用 4 楼 Loaden 的回复:]
最近在考虑函数速度的优化问题。一般函数分为普通函数和inline函数,因为既然inline是编译器展开,那么我何不手动展开试试呢。在频繁访问数据的情况下,他们各自的速度对比是怎样的?
通常情况,inline比普通调用要快,但是,如果我是通过对象A调用访问对象B的数据呢?普通函数相对inline真的慢?inline手动展开了,要好几次访问B,然后再访问数据;而普通的调用,只需要访问一次B的调用;手动展开了,会不会比编译器展开的…
[/Quote]
falcon_cjj 2009-06-14
  • 打赏
  • 举报
回复
全看编译器的。。基本你的设定起不了什么作用
机智的呆呆 2009-06-12
  • 打赏
  • 举报
回复
程序应当在算法和架构上优化,语句上优化没什么意思,现在编译器对于语句优化能力太强大了~~~~
所以也不要过于迷信inline这种语句级的优化。
zxbgy 2009-06-12
  • 打赏
  • 举报
回复
严重同意ls的意见。。。。
光宇广贞 2009-06-12
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 Loaden 的回复:]
最近在考虑函数速度的优化问题。一般函数分为普通函数和inline函数,因为既然inline是编译器展开,那么我何不手动展开试试呢。在频繁访问数据的情况下,他们各自的速度对比是怎样的?
通常情况,inline比普通调用要快,但是,如果我是通过对象A调用访问对象B的数据呢?普通函数相对inline真的慢?inline手动展开了,要好几次访问B,然后再访问数据;而普通的调用,只需要访问一次B的调用;手动展开了,会不会比编译器展开的…
[/Quote]

手动尝试的优化干不过编译器是显而易见的结论,我就算改用内联汇编,也干不过编译器。

C/C++默认的函数调用规范是__cdecl,这对编译器进行堆栈调用优化是有优势的。你改为 __stdcall 效果可能就不同了。

看汇编码,不一定能看出什么来。我曾试过,为了干得过编译器,我反汇编查看汇编码,并原模原样地嵌入内联汇编,和编译器的C/C++拼,还是没有拼过……这事儿很新鲜。

目前没有什么新的觉悟,总之,编译器比较无敌。
pathuang68 2009-06-12
  • 打赏
  • 举报
回复
天外飞仙兄绝对是个人才!赞!!
「已注销」 2009-06-11
  • 打赏
  • 举报
回复
最近在考虑函数速度的优化问题。一般函数分为普通函数和inline函数,因为既然inline是编译器展开,那么我何不手动展开试试呢。在频繁访问数据的情况下,他们各自的速度对比是怎样的?
通常情况,inline比普通调用要快,但是,如果我是通过对象A调用访问对象B的数据呢?普通函数相对inline真的慢?inline手动展开了,要好几次访问B,然后再访问数据;而普通的调用,只需要访问一次B的调用;手动展开了,会不会比编译器展开的快呢,而且或许还可以做些手动优化。
以下用了一个很简单的例子,做了一个简要的测试。

#include<cstdio>;

#include <windows.h>

#pragma comment( lib,"winmm" )

#define C 10*1000*1000

namespace speed
{
class testImpl
{
public:
testImpl( void ) : data( 0 ) {}
void clear( void ) { data = 0; }
void test1( void )
{
for( unsigned long long i = 0ULL; i < C; ++i )
{
++data;
}
}
inline void test2( void )
{
for( unsigned long long i = 0ULL; i < C; ++i )
{
++data;
}
}
int data;
};
class testClass
{
public:
testImpl *m_Impl;
public:
testClass( void )
{
m_Impl = new testImpl();
}
~testClass( void )
{
delete m_Impl;
}
void test1( void )
{
m_Impl->test1();
m_Impl->clear();
}
void test2( void )
{
m_Impl->test2();
m_Impl->clear();
}
void test3( void )
{
for( unsigned long long i = 0ULL; i < C; ++i )
{
++m_Impl->data;
}
m_Impl->clear();
}
};
static void test( void )
{
testClass aTest;
::timeBeginPeriod( 1 );
int t0 = ::timeGetTime();
aTest.test1();
int t1 = ::timeGetTime();
aTest.test2();
int t2 = ::timeGetTime();
aTest.test3();
int t3 = ::timeGetTime();
::timeEndPeriod( 1 );
std::printf( "time of normal/inline/expand : %d/%d/%d\r\n",t1-t0,t2-t1,t3-t2 );
std::printf( "value = %d",aTest.m_Impl->data );
}
};

在我的机器上(AMD Althon XP 2200+ 512M)得到了以下平均值(多次输出,比较趋向中间值的结果):
debug :
time of normal/inline/expand : 84/67/85
value = 0
release:
time of normal/inline/expand : 36/16/19
value = 0
--------------------next---------------------

re: 几种函数形式的速度比较
首先我假设你的test2()真的在testClass::test2()内被展开.
其伪码应该为:
void testClass::test2( void )
{
/**testImpl::test2() begin**/
{
testImpl* const __impl=m_Impl;
for( unsigned long long i = 0ULL; i < C; ++i )
{
__impl->++data;
}
}
/**testImpl::test2() end**/
m_Impl->clear();
}

而testImpl::test1()又会是什么?
因为C++规定non-virtual member function其调用成本等同一个普通函数调用, 因此testImpl::test1()所对应的C伪码应该是:
void __testImpl_test1(testImpl *const This){
for( unsigned long long i = 0ULL; i < C; ++i )
{
This->++data;
}
}

而testClass::test1()则变为
void __testClass_test1(testClass *const This){
__testImpl_test( &This->m_Impl );
....
}

也就是不会出现"inline其实就是展开,那么,要多次通过B对象访问数据,要多次取B的地址,再取数据。"这种情况.
或者说testClass::test2()比testClass::test1()省了出入栈时间而已.
如果你是用VC编绎的话, 据我所知必需要用参数强迫编绎器才会内联展开.
还有就是类成员函数分为: inline, static, virtual, friend四大类.
而调用效率区别最大的是non-virtual和virtual,
你所比较的两种都是non-virtual所以效率并不会有太大的差别.
2005-12-12 00:21 |

--------------------next---------------------

re: hpho
1. 可能你写的比较匆忙,或者说应为是伪码,不过,稍微有些问题。
2. 对virtual和非virtual 实在没什么好比的
3. friend只不过是一个申明,另外个人唯恐避之不急
4. 很容易的,我们都会容易想的将多次访问改为本地访问,正如release对test3展开的优化(对比debug很能说明问题)
void test3( void )
{
testImpl *impl = m_Impl;
for( unsigned long long i = 0ULL; i < C; ++i )
{
++impl->data;
}
impl->clear();
}
4. 为什么这样展开后test3比test2还要慢呢?也就是还是inline快呢?所以,我觉得以上数据或许能说明点什么。
5. 这样一次记录,下次,我可以免去再测试。当然,inline的情况不同,或许另当别论。
6. 毫无疑问,我们常采用的本对象函数访问的inline,显然最快,所以,我只是测试一下AB访问的情况是否会慢一点(因为我开始这么觉得,多次的频繁,开销应该比压盏出盏高,我手动的局部化可能要快,那到底情况如何呢)。
2005-12-12 09:33 |

--------------------next---------------------

re: hpho
测试结果和给编译器自动优化结果基本一样。不过,很遗憾的是,当我打算看看汇编码时,debug下的test1和test2得到了一样的结果(即使我强制inline),release,编译器甚至直接跳到test1去了。那么也就是编译器对这个循环没有inline(也怪自己debug和release下看到输出差别,就没细究)。而对于手动展开,当我为了避免干扰,扩大循环次数时,结果表现是最差的。
但,不管怎么说,我们可以认为inline(如果能够,它还是最优的)是个不错的选择,而手动的优化,显然失败了。
另外,输出结果的差异,可能有较大的扰动(必要时,还需要足够的放大,甚至调用先后的调整——这个顺序,我怀疑和cache有关)。

附,以下是MSDN关于内联的说明(最后一句话很重要):
内联函数展开”(/Obn) 选项控制函数的内联展开,其中 n 是下列之一:
选项 说明
/Ob0 禁用内联展开(默认情况下是打开的)。
/Ob1 只展开标记为 inline 或 __inline 的函数,或在类声明内定义的 C++ 成员函数中的函数。
/Ob2 展开标记为 inline 或 __inline 的函数和编译器选择的任何其他函数(由编译器自行进行展开,通常称作自动内联)。
当使用 /O1、/O2 或 /Ox 时 /Ob2 有效。

此选项要求使用 /O1、/O2、/Ox 或 /Og 启用优化。

编译器将内联展开选项和关键字视为建议。不保证函数将内联展开。无法强制编译器内联特定函数。
「已注销」 2009-06-11
  • 打赏
  • 举报
回复
/Ob0 禁用内联展开(默认情况下是打开的)。 /Ob1 只展开标记为 inline 或 __inline ... /Ob2 展开标记为 inline 或 __inline 的函数和编译器选择的任何其他函数(由编译器自行 ... 不保证函数将内联展开。
lylm 2009-06-11
  • 打赏
  • 举报
回复
inline放在前面
「已注销」 2009-06-11
  • 打赏
  • 举报
回复
inline int add(int i)
{
i++;
return i;
}

inline放在前面。

inline只是建议,具体由编译器决定是否内联。
另,可以使用/Ob2来强制内联。

33,317

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧