21ic电子技术开发论坛

标题: 使用内联函数和内嵌汇编有什么好处? [打印本页]

作者: 思行合一    时间: 2010-11-7 12:37
标题: 使用内联函数和内嵌汇编有什么好处?
使用内联函数和内嵌汇编有什么好处?

作者: yoyowodeai    时间: 2010-11-7 12:41
C代码编译输出的结果在功能上与汇编程序是等价的,但实际上他们完全不同!

作者: -自己人    时间: 2010-11-7 13:05
[9.1] 内联函数是什么?

内联函数是代码被插入到调用者代码处的函数。如同 #define 宏,内联函数通过避免被调用的开销来提高执行效率,尤其是它能够通过调用(“过程化集成”)被编译器优化。

[ Top | Bottom | Previous section | Next section ]

[9.2] 内联函数是如何在安全和速度上取得折衷?

在 C 中,你可以通过在结构中设置一个 void* 来得到“封装的结构”,在这种情况下,指向实际数据的 void* 指针对于结构的用户来说是未知的。因此结构的用户不知道如何解释void*指针所指内容,但是存取函数可以将 void* 转换成适当的隐含类型。这样给出了封装的一种形式。

不幸的是这样做丧失了类型安全,并且也将繁琐的对结构中的每个域的访问强加于函数调用。(如果你允许直接存取结构的域,那么对任何能直接存取的人来说,了解如何解释 void* 指针所指内容就是必要的了;这样将使改变底层数据结构变的困难)。

虽然函数调用开销是很小的,但它会被累积。C++类允许函数调用以内联展开。这样让你在得到封装的安全性时,同时得到直接存取的速度。此外,内联函数的参数类型由编译器检查,这是对 C 的 #define 宏的一个改进。

[ Top | Bottom | Previous section | Next section ]

[9.3] 为什么我应该用内联函数?而不是原来清晰的 #define 宏? UPDATED!
[Recently rewrote the sentence on #define being evil (on 7/00). Click here to go to the next FAQ in the "chain" of recent changes.]

因为#define宏是在四处是有害的:罪状#1, 罪状#2, 罪状#3, 和 罪状#4。

和 #define 宏不同的是,内联函数总是对参数只精确地进行一次求值,从而避免了那声名狼藉的宏错误。换句话说,调用内联函数和调用正规函数是等价的,差别仅仅是更快:
// 返回 i 的绝对值的宏
#define unsafe(i)  \
         ( (i) >= 0 ? (i) : -(i) )

// 返回 i 的绝对值的内联函数
inline
int safe(int i)
{
   return i >= 0 ? i : -i;
}

int f();

void userCode(int x)
{
   int ans;

   ans = unsafe(x++);   // 错误!x 被增加两次
   ans = unsafe(f());   // 危险!f()被调用两次

   ans = safe(x++);     // 正确! x 被增加一次
   ans = safe(f());     // 正确! f() 被调用一次
}

和宏不同的,还有内联函数的参数类型被检查,并且被正确地进行必要的转换。

宏是有害的;非万不得已不要用。

[ Top | Bottom | Previous section | Next section ]

[9.4] 如何告诉编译器使非成员函数成为内联函数?

声明内联函数看上去和普通函数非常相似:

void f(int i, char c);

当你定义一个内联函数时,在函数定义前加上 inline 关键字,并且将定义放入头文件:

inline
void f(int i, char c)
{
   // ...
}

注意:将函数的定义({...}之间的部分)放在头文件中是强制的,除非该函数仅仅被单个 .cpp 文件使用。尤其是,如果你将内联函数的定义放在 .cpp 文件中并且在其他 .cpp文件中调用它,连接器将给出 “unresolved external” 错误。

[ Top | Bottom | Previous section | Next section ]

[9.5] 如何告诉编译器使一个成员函数成为内联函数?

声明内联成员函数看上去和普通函数非常类似:

class Fred {
public:
   void f(int i, char c);
};

但是当你定义内联成员函数时,在成员函数定义前加上 inline 关键字,并且将定义放入头文件中:

inline
void Fred::f(int i, char c)
{
   // ...
}

通常将函数的定义({...}之间的部分)放在头文件中是强制的。如果你将内联函数的定义放在 .cpp 文件中并且在其他 .cpp 文件中调用它,连接器将给出“unresolved external”错误。

[ Top | Bottom | Previous section | Next section ]

[9.6] 有其它方法告诉编译器使成员函数成为内联吗?

有:在类体内定义成员函数:

class Fred {
public:
   void f(int i, char c)
     {
       // ...
     }
};

尽管这对于写类的人来说很容易,但由于它将类是“什么”(what)和类“如何”(how)工作混在一起,

作者: hotpower    时间: 2010-12-26 10:27
农会发放棉裤一条以资鼓励

普及教育是美得

作者: vigorshaka    时间: 2010-12-26 18:53
内联函数可以理解成快速跳转到对应函数地址,而不是用长跳转指令,不使用或者少使用堆栈资源。

作者: liuq    时间: 2010-12-26 19:08
内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。
内联函数可以调试,而宏定义是不可以调试的。
内联函数与宏本质上是两个不同的概念。

作者: xwj    时间: 2010-12-26 19:10
本帖最后由 xwj 于 2010-12-26 19:16 编辑

5楼理解错误。
不是什么快速跳转,而是将函数代码直接插入(复制)到每个调用的位置,以空间换时间

作者: liuq    时间: 2010-12-26 19:12
7楼:请多多指教,我没有说快速跳转吧。

作者: xwj    时间: 2010-12-26 19:15
呵呵,你回复太快,插楼了:lol

作者: liuq    时间: 2010-12-26 19:20
三四年前我做了一个软件模拟仿真器,除仿真CPU指令外还需要仿真USB/7816等等外设,在当时2.8G主频CPU的情况下(大致相当于每秒10亿条用户指令),仿真速度达到近4mips,这是几乎在全部使用内联函数下实现的。
只要将inline少少的去除,速度几乎是一个数量级的指标下降。
如果程序编写者对于既要求快速,又要求可读的情况下,则应该将函数冠以inline。

作者: txcy    时间: 2010-12-26 22:13
了解了一点

作者: bit6019    时间: 2011-1-31 22:46
反正好像是程序编译快点

作者: wu0232    时间: 2011-2-2 20:14
mark~~~

作者: bit6019    时间: 2011-2-8 22:42
内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。
内联函数可以调试,而宏定义是不可以调试的。
内联函数与宏本质上是两个不同的概念。

可真是讲到点子上了

作者: 3B1105    时间: 2011-2-12 10:58
受教了

作者: 黑发尤物    时间: 2011-2-15 17:39
领教了,:victory:

作者: 即时生效    时间: 2011-2-16 17:18
mark

作者: wu0232    时间: 2011-2-19 09:26
mark

作者: HXW718059156    时间: 2011-2-19 10:58
受教了~!

作者: yybj    时间: 2011-2-19 21:11
这个还真没怎么用过

作者: 米其林r    时间: 2011-2-19 22:07
编译速度和执行速度快

作者: 火箭球迷    时间: 2011-2-20 18:51
真正用到时就觉得好了

作者: 无冕之王    时间: 2011-2-21 09:03
这个我好像也用的比较少





欢迎光临 21ic电子技术开发论坛 (https://bbs.21ic.com/)