0
点赞
收藏
分享

微信扫一扫

MySQL、SQL SERVER、Oracle、PostgreSQL常用内置函数

花海书香 2023-06-04 阅读 83

目录

 1. 知识引入

2. 知识点讲解

2.1 内联函数的使用

2.2 内联函数的特性 

2.2 内联函数的注意点

3. 面试题


 1. 知识引入

在学C语言的宏时,我们了解了宏函数的概念与用法。我们也知道宏函数有一些易错点,稍不注意就可能出错!你若过不相信的话,就别看下面的代码自己写一个 a + b 的宏函数。

#define ADD(a, b) ((a) + (b))

int main()
{
cout << ADD(10, 20) << endl;
return 0;
}

不知道UU们写对了吗?为什么说宏函数容易写错呢?我们知道红的特性就是替换,这种特性会使我们遇到一些难以避免的错误,我们来看看这些常见的错误:

不加外面的括号替换之后由于运算符的优先级问题,导致结果出错!

#define ADD(a, b) (a) + (b)

int main()
{
cout << ADD(10, 20) * 2 << endl; //使用宏函数
cout << (10) + (20) * 2 << endl; //宏函数替换之后
return 0;
}

 下面的代码同样也存由于运算符的优先级产生的问题:加法的优先级更高,导致结果出错。

#define ADD(a, b) (a + b)

int main()
{
int a = 1, b = 2;
cout << ADD(a | b, a & b) << endl; //使用宏函数
cout << (a | b + a & b) << endl; //宏函数替换之后
return 0;
}

那你可能会说了:那我每次都想正确的写法那样,多加几个括号不就能避免这种错误啦!很遗憾因为宏的替换特性,有些错误难以避免,观察如下代码:

我们尝试利用一个宏函数求解 b 的平方,但是我们用 ++b 来使用该函数,替换之后 ++b 会被执行两次,显然最终的结果并不是我们想要的。

#define Square(a) ((a) * (a))

int main()
{
int b = 2;
cout << Square(++b) << endl; //使用宏函数
cout << ((++b) * (++b)) << endl; //宏函数替换之后
return 0;
}

 但是呢宏还是有优点的,下面我们就来看看宏的优缺点:

C++ 是既想要宏的优点,又不想要宏的缺点。因此C++引入了内联函数。

2. 知识点讲解

2.1 内联函数的使用

用法很简单,我们只要在一个函数返回值的前面加上 inline 关键字即可。像这样:

inline int Add(int x, int y)
{
return x + y;
}


int main()
{
cout << Add(2, 3) << endl;
return 0;
}

2.2 内联函数的特性 

再来看看内联函数的概念吧:

这里的在调用内联函数的地方展开,指的是:内联函数经过编译之后,会直接在调用处转化成汇编代码,而不是通过 call 指令,跳转到函数的实际地址处进行函数汇编代码的执行。 

在VS2019的debug模式下,默认是不会对程序进行优化的,我们看不到内联函数的展开,但是在release模式下又不支持调试,因此我们需要进行相关的设置才能看到内联函数的展开。

在项目---->属性中更改下面的设置即可 

我们通过调试下面的代码,然后查看汇编代码之后发现 Add 函数的调用并不是 call 函数地址而是直接在函数调用的地方展开,变成了汇编代码。

2.2 内联函数的注意点

通过上面的调试过程我们直到内联函数是直接在调用处展开的,因此内联函数并没有函数地址。也就是说,内联函数不会出现在符号表中,也就意味着内联函数不可使用函数定义与函数声明分开的写法。

 为什么会报错呢?UU们不妨结合编译,链接的相关知识想一想。 

Add函数是内联函数,在调用Add函数的地方,编译器会在调用的地方展开。但是在调用Add函数的源文件中,只有Add函数的声明。 编译器无法做到在调用的地方展开,于是编译器会尝试通过 call 指令去调用函数,但是内联函数不会在符号表中出现,就会找不到函数的地址。因此会出现链接错误。

因此我们得出一个重要的结论:内联函数的声明与定义不可分离。

那应该怎么解决这个问题呢?很简单,直接在头文件里面写内联函数的定义即可。

3. 面试题

 

举报

相关推荐

0 条评论