C++入门篇--内联函数和extern关键字

内联函数

在学习函数栈帧时我们知道,只要我们去调用函数,就会在栈上开辟一个空间用来。每次去调用的时候会有一些时间开销。但是在学习C语言的时候我们学习过一个叫做宏的东西,比如下面的代码。

#define ADD(A,B) ((A) + (B))
int add(int x, int y){
    return x+y;
}
int main(){
    int a = ADD(1, 2); // 调用宏
    int b = add(1, 2); // 调用函数
    return 0;
}

这两种方式都可以实现两个数求和的功能,那么这两种方式有什么区别呢?在调用函数实现两个数相加时,会在栈上开辟一个空间用来存放函数,调用多少次就开辟多少个空间,在函数使用完后就会释放掉栈上的空间。如果使用宏,会在程序的编译阶段就先将这个表达替换掉,就不存在在栈上开辟空间的情况。

#define ADD(A, B) ((A)+(B))
int main(){
    int a = ADD(1, 2); // 在程序编译的时候这条语句会被替换掉,即
    // int a = ((1) + (2));
    return 0;
}

用宏这种方式虽然可以省去程序在栈上开辟空间的这一步,但是,写宏是一件很蛋疼的是,因为宏和函数不一样,它完全替换的,所以写起来很麻烦。所以,C中就引入了一个新的玩意,叫内联函数

概念

inline修饰的函数就叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。

在这里插入图片描述

这是一个一般的函数调用,我们可以发现,程序在编译的时候是对其进行跳转,也就是说,函数在被调用的时候是在栈上开辟了空间的。那么下面我们看看内联函数:

在这里插入图片描述

特性
  • inline是一种以空间换时间的做法,省去调用函数额外开销。所以代码很长或者有循环或递归的函数都不适宜使用作为内联函数
  • inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等,编译器优化时会忽略掉内联。
  • inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

extern “c”

有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern"C",意思是告诉编译器,将该函数按照C语言规则来编译。比如:tcmalloc是google用C++实现的一个项目,它提供tcmalloc()和tcfree两个接口来使用,但如果是C项目就没办法使用,因为我们知道C语言和C++在函数的处理上有些不同的地方,C++有命名修饰,那么就可以使用exturn"C" 来解决这一问题。语法如下

// 在C++中
exturn "c" int Add(int left, int right);

这样在C中语言环境实现的函数,C++环境下也可以正常使用。关键字exturn"C",就是告诉C++编译器函数Add是按照C语言的命名规则来编译链接的,此时C++编译器就会按照c语言的函数名去函数列表找这个函数。


那么,怎么让c语言使用C++编译生成的函数呢?答案同样是使用extern"C"来实现,不过这次会稍微困难一点。

//  头文件
#ifdef __cplusplus  // __cplusplus是C++编译器自己定义的
extern "C"
{
#endif
    void StackInit(ST* ps);
    void StackDestroy(ST* ps);
    void StackPush(ST* ps);
    void StackPop(ST* ps);
#ifdef __cplusplus
}
#endif

这几行代码的意思是C++编译器将按照c语言的方式来处理函数。这样在C语言中使用这个库的时候,也能正确链接到函数。

—end

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
回答: C++中的函数宏定义和内函数有一些区别。函数宏定义是在预编译阶段将宏名替换为宏体,它不是真正的函数,而是一种字符串替换的机制。宏定义没有类型检查,无论对还是错都会直接替换。而内函数是真正的函数,使用inline修饰,编译器会在调用内函数的地方展开,没有函数压栈的开销,提高了程序的运行效率。内函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,如while、switch,并且内函数本身不能直接调用自身。如果内函数函数体过大,编译器会自动将其变为普通函数。内函数在编译阶段进行代码插入,而宏定义是在预编译阶段进行代码展开。因此,内函数在编译时会进行类型检查,而宏定义没有类型检查。此外,内函数的使用可以提高程序的效率,而宏定义的使用可以省去函数调用的开销。\[1\]\[2\] 然而,需要注意的是,宏定义和内函数在使用时都是进行代码展开。对于宏定义,预处理器会将所有的宏名替换为宏体;而对于内函数,编译器会在每处调用内函数的地方直接将内函数的内容展开。这样可以省去函数压栈退栈的开销,提高了程序的效率。\[2\] 举个例子来说明宏定义和内函数的区别。假设有以下代码: #include <iostream> using namespace std; #define MAX(a,b) (a > b ? a:b) int main() { int a = 10; int b = 20; cout << MAX(a, ++b) << endl; return 0; } 这段代码中,宏定义MAX(a, b)会将a和b进行比较,并返回较大的值。在调用MAX(a, ++b)时,宏定义会将其展开为(a > ++b ? a:b)。由于宏定义是字符串替换,所以++b会被展开两次,导致b的值增加了两次。因此,输出结果为22。\[3\] #### 引用[.reference_title] - *1* *3* [C++:在代码中理解宏定义和内函数](https://blog.csdn.net/qq_43825377/article/details/116211242)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [C++中内函数和宏定义](https://blog.csdn.net/luolaihua2018/article/details/115377860)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_yiyi_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值