> 🍃 本系列为初阶C++的内容,如果感兴趣,欢迎订阅🚩
> 🎊个人主页:[小编的个人主页])小编的个人主页
> 🎀 🎉欢迎大家点赞👍收藏⭐文章
> ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍
目录
🐼inline
🐼nullptr
🐼inline
- 🌟在C语言阶段,我们学习了宏,并学习了宏函数的用法。比如写一个加法的宏函数:#define Add(x,y) ((x)+(y))由于C语言宏函数的容易出错,不一小心就会使逻辑错误,比如:为什么不能加分号?为什么要加外层括号?为什么要加内层括号?而且宏函数还不能调试(都是在编译期间已经完成替换)。如果在这里发生逻辑错误,我们很难发现。所以C++设计了inline目的就是替代C的宏函数。
- 所以在C++中,引入了内联函数(inline)。用inline修饰的函数叫做内联函数,在编译区间,编译器会将内联函数展开,这样就不需要建立函数栈帧,提高了效率。
- 需要注意vs编译器debug版本下面默认是不展开inline的,目的是方便调试,debug版本想展开需要设置⼀下以下两个地方。
第一步:
第二步:
我们可以从汇编层看内联函数是否展开
对于这段内联函数:
#define _CRT_SECURE_NO_WARNINGS #include <malloc.h> #include<iostream> using namespace std; inline int Add(int x, int y) { int ret = x + y; ret += 1; return ret; } #include"F.h" int main() { // 可以通过汇编观察程序是否展开 // 有call Add语句就是没有展开,没有就是展开了 int ret = Add(1, 2); cout << Add(1, 2) * 5 << endl; return 0; }
没设置之前:
我们发现,内联函数发生了调用,没有展开,说明vs默认是不展开的。
通过刚刚两步设置修改后:
✨经过修改,我们发现,在vs中,编译器默认不展开inline函数,而我们修改后,inline函数在编译期间直接展开。
- 🌟inline对于编译器而言只是⼀个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适用于频繁调用的短小函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。具体最后inline函数是否展开取决于编译器。
- inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。 对于编译器而言,编译器回去找函数的地址,但是内联函数如果展开,在链接期间:在符号表中是默认不存在的,所以编译器找不到内联函数的首地址,发生了链接错误。
如:
//test.cpp #include"F.h" int main() { // 可以通过汇编观察程序是否展开 // 有call Add语句就是没有展开,没有就是展开了 int ret = Add(1, 2); cout << Add(1, 2) * 5 << endl; f(1);//call(0x) //f(); return 0; } #pragma once // F.h #include <iostream> using namespace std; inline void f(int i); //F.cpp #define _CRT_SECURE_NO_WARNINGS // F.cpp #include "F.h" inline void f(int i) { cout << i << endl; }
会发生链接错误,编译器报错: "void __cdecl f(int)" (?f@@YAXH@Z),函数 main 中引用了该符号.这正是因为内联函数的声明和定义分开,导致的。
🐼nullptr
🌟在C语言中,NULL本质上是宏。
但是C++中NULL可能被定义为字面常量0,或者C中被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,本想通过f(NULL)调用指针版本的 f(int*)函数,但是由于NULL被定义成0,调用了f(intx),因此与程序的初衷相悖。f((void*)NULL); 调用会报错。
如:
#include<iostream> using namespace std; void f(int x) { cout << "f(int x)" << endl; } void f(int* ptr) { cout << "f(int* ptr)" << endl; } int main() { f(0); // 本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于NULL被定义成0,调⽤了f(int x),因此与程序的初衷相悖。 f(NULL); f((int*)NULL); // 编译报错:error C2665: “f”: 2 个重载中没有⼀个可以转换所有参数类型 // f((void*)NULL); f(nullptr); return 0; }
运行结果:
f(int x)
f(int x)
f(int* ptr)
f(int* ptr)C++11中引入nullptr,nullptr是⼀个特殊的关键字,nullptr是⼀种特殊类型的字面量,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,而不能被转换为整数类型。
感谢你看到这里,如果觉得本篇文章对你有帮助,点个赞👍 吧,你的点赞就是我更新的最大动力。⛅️🌈 ☀️