当前位置:   article > 正文

C语言 内联函数_c语言内联函数

c语言内联函数

【注:本文只讨论C语言中的内联函数,暂不谈论C++,因为C++中这块知识相对要更复杂。】

什么是内联函数

在C语言中,如果一些函数被频繁调用,不断地有函数入栈,即函数栈,会造成栈空间或栈内存的大量消耗。
为了解决这个问题,特别的引入了inline修饰符,表示为内联函数。
内联函数是代码被插入到调用者代码处的函数。内联函数通过避免被调用的开销来提高执行效率

采用内联函数实质是以空间换时间的做法

举例:

void myprintf(int a)
{
	printf(%d”,a);
}

int main()
{
	for(i=0;i<100;i++myprintf(i);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

对于这个函数,在进行反复的打印i的过程中我们是不是要反复的调用myprintf()这个函数,进函数和出函数是需要时间的(入栈出栈),假设这个过程用时为4ms,而执行printf这个操作只需要2ms,那么在100次循环的过程中进出函数的时间比函数功能printf需要的时间还要长,这样很影响工作效率。于是,我们就想要如何避免进出函数的过程呢?可以声明inline这个关键字。

inline void myprintf(int a)
{
	printf(%d”,a);
}

int main()
{
	for(i=0;i<100;i++myprintf(i);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

main函数中的myprintf(i);会直接替换成该函数主体,上面的代码在编译时实际上是这样的:

inline void myprintf(int a)
{
	printf(%d”,a);
}

int main()
{
	for(i=0;i<100;i++{
		printf(%d”,i);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

内联函数和宏定义区别

内联函数看上去和宏定义非常相似。
对于上面的例子,我们可以用宏定义实现:

#define MYPRINTF(a)  printf(“%d”,a);

int main()
{
	for(i=0;i<100;i++MYPRINTF(i);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

效果可以说与前面使用内联的方式没多大差别。
但宏定义在某些情况下会有问题,比如:

// 返回 i 的绝对值的宏
#define abs1(i) \
         ( (i) >= 0 ? (i) : -(i) )

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


int fun();

void userCode(int x)
{
   int ans;

   ans = abs1(x++);   // 错误!x 被增加两次
   ans = abs1(fun());   // 错误!fun()被调用两次

   ans = abs2(x++);     // 正确! x 被增加一次
   ans = abs2(fun());     // 正确! fun() 被调用一次
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

ans = abs1(x++); 展开是ans = ( (x++) >= 0 ? (x++) : -(x++) );
所以x++会执行2次,这可能是用户所不希望的。

内联函数,与直接的函数调用区别仅在于没有函数调用过程的消耗。保留了函数调用的特性,又提高函数的执行效率。

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

使用内联函数注意事项

1、inline只适合函数体内代码量少的函数使用,因为每一处内联函数的调用都要复制代码,如果该函数代码量较大,将使程序的总代码量增大,消耗更多的内存空间。

2、内联函数本身不能是直接递归函数(自己内部还调用自己的函数)。因为这样会在编译时无穷无尽地展开。

3、如果执行函数体内代码的时间,相比于函数调用的时间开销较大,那么使用内联的效率的收获会很少。比如函数内有循环,这种情况就不考虑用内联函数了。

4、关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。

inline void Foo(int x, int y); // inline 仅与函数声明放在一起
void Foo(int x, int y)
{
}
  • 1
  • 2
  • 3
  • 4

5、对于功能复杂,内容较多的函数,即使加上inline修饰符,也不一定能作为内联函数,因为编译器会判定做优化。

关于static inline

static inline的内联函数,一般情况下不会产生函数本身的代码,而是全部被嵌入在被调用的地方。如果不加static,则表示该函数有可能会被其他编译单元所调用,所以一定会产生函数本身的代码。所以加了static,一般可令可执行文件变小。—【存疑,不确定】

static inline的内联函数,只能在本文件内调用,而没有static则可以被其他文件调用,这与static的常用方法一致。

函数的地址被使用的时候。如通过函数指针对函数进行了间接调用。这种情况下就不得不为static inline函数生成独立的汇编码,否则它没有自己的地址。

参考鸣谢:

https://blog.csdn.net/zqixiao_09/article/details/50877383

https://www.cnblogs.com/linux-bfbdxj520/p/11405474.html

https://www.jb51.net/article/41520.htm

https://blog.csdn.net/chuqierliang/article/details/48053417

https://blog.csdn.net/weixin_33895657/article/details/92037511

https://blog.csdn.net/qq_33757398/article/details/81390151

https://blog.csdn.net/weixin_30706507/article/details/96192546

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/626821
推荐阅读
相关标签
  

闽ICP备14008679号