持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情。
1.1.14 说说静态局部变量,全局变量,局部变量的特点,以及使用场景
参考回答
-
首先从作用域考虑:C++里作用域可分为6种:全局,局部,类,语句,命名空间和文件作用域。
全局变量:全局作用域,可以通过extern作用于其他非定义的源文件。
静态全局变量 :全局作用域+文件作用域,所以无法在其他文件中使用。
局部变量:局部作用域,比如函数的参数,函数内的局部变量等等。
静态局部变量 :局部作用域,只被初始化一次,直到程序结束。
-
从所在空间考虑:除了局部变量在栈上外,其他都在静态存储区。因为静态变量都在静态存储区,所以下次调用函数的时候还是能取到原来的值。
-
生命周期: 局部变量在栈上,出了作用域就回收内存;而全局变量、静态全局变量、静态局部变量都在静态存储区,直到程序结束才会回收内存。
-
使用场景:从它们各自特点就可以看出各自的应用场景,不再赘述。
1.1.15 说说内联函数和宏函数的区别
参考回答
区别:
- 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率;而内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。
- 宏函数是在预编译的时候把所有的宏名用宏体来替换,简单的说就是字符串替换 ;而内联函数则是在编译的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样可以省去函数的调用的开销,提高效率
- 宏定义是没有类型检查的,无论对还是错都是直接替换;而内联函数在编译的时候会进行类型的检查,内联函数满足函数的性质,比如有返回值、参数列表等
答案解析
//宏定义示例
#define MAX(a,b) ((a)>(b)?(a):(b))
MAX(a,"Hello"); //错误地比较int和字符串,没有参数类型检查
//内联函数示例
#include <stdio.h>
inline int add(int a, int b){
return (a + b);
}
int main(void){
int a;
a = add(1, 2);
printf("a+b=%d\n", a);
return 0;
}
//以上a = add(1, 2);处在编译时将被展开为:a = (a + b);
1、使用时的一些注意事项:
- 使用宏定义一定要注意错误情况的出现,比如宏定义函数没有类型检查,可能传进来任意类型,从而带来错误,如举例。还有就是括号的使用,宏在定义时要小心处理宏参数,一般用括号括起来,否则容易出现二义性
- inline函数一般用于比较小的,频繁调用的函数,这样可以减少函数调用带来的开销。只需要在函数返回类型前加上关键字inline,即可将函数指定为inline函数。
- 同其它函数不同的是,最好将inline函数定义在头文件,而不仅仅是声明,因为编译器在处理inline函数时,需要在调用点内联展开该函数,所以仅需要函数声明是不够的。
2、内联函数使用的条件:
- 内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率 的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联:
- (1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
- (2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
- 内联不是什么时候都能展开的,一个好的编译器将会根据函数的定义体,自动地取消不符合要求的内联。
1.1.16 说说运算符i++和++i的区别
参考回答
先看到实现代码:
#include <stdio.h>
int main(){
int i = 2;
int j = 2;
j += i++; //先赋值后加
printf("i= %d, j= %d\n",i, j); //i= 3, j= 4
i = 2;
j = 2;
j += ++i; //先加后赋值
printf("i= %d, j= %d",i, j); //i= 3, j= 5
}
-
赋值顺序不同:++ i 是先加后赋值;i ++ 是先赋值后加;++i和i++都是分两步完成的。
-
效率不同:后置++执行速度比前置的慢。
-
i++ 不能作为左值,而++i 可以:
int i = 0; int *p1 = &(++i);//正确 int *p2 = &(i++);//错误 ++i = 1;//正确 i++ = 1;//错误 -
两者都不是原子操作。