总结嵌入式软开常问C/C++问题-1

1、指针和引用的区别?

(1)指针是一个变量,存储的是变量的地址,引用是变量的别名,内部实现是只读指针;

(2)指针可以为空,引用不能为空,定义时必须初始化;

(3)指针在初始化之后可以改变指向,引用在初始化之后不能改变;

(4)指针可以有多级,引用只有一级;

(5)当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,二者指向的地址相同,但不是同一个变量,在函数中改变该变量的指向不影响实参,而引用是可以的;

(6)指针是具体变量,需要占用存储空间,引用的本质是一个指针,会占据4个字节的内存;

2、堆和栈的区别

(1)堆和栈在空间分配方面的区别:

堆一般由程序员分配释放,如果程序员不释放,程序结束后可能有操作系统回收,分配方式类似于链表。栈一般由操作系统自动分配释放,存放函数的参数值和局部变量的值等,操作方式类似于数据结构中的栈。

(2)堆和栈在缓存方式方面的区别:

堆存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定,所以调用这些对象的速度比较慢。栈使用一级缓存,通常是被调用时处于存储空间中,调用完毕后立即释放。

(3)堆和栈在数据结构方面的区别:

堆一般被看做一棵树,比如堆排序。栈是一种先进后出的数据结构。

3、关键字static的作用是什么?

在C语言中static用来修饰局部静态变量和外部静态变量和函数,而C++语言还可以用来定义类的成员变量和函数,即静态成员和静态成员函数,C++的静态成员可以在多个对象实例之间进行通信,传递信息。

(1)定义全局静态变量和局部静态变量:在变量前面加上static关键字。初始化的静态变量会在.data段分配内存,未初始化的静态变量会在.bss段分配内存。直到程序结束,静态变量始终会维持前值。只不过全局静态变量和局部静态变量的作用域不一样;

(2)定义静态函数:在函数返回类型前加上static关键字,函数被定义为静态函数。静态函数只能在本源文件中使用;

(3)在变量类型前加上static关键字,变量即被定义为静态变量。静态变量只能在本源文件中使用,比如:

static int a;

static void func();

(4)在C++中,static关键字可以用于定义类中的静态成员变量:使用静态数据成员,它既可以被当成全局变量那样去存储,但又被隐藏在类的内部。类中的static静态数据成员拥有一块单独的存储区,而不管创建了多少个该类的对象。所有这些对象的静态数据成员都共享这一块静态存储空间。

(5)在C++中,static关键字可以用于定义类中的静态成员函数:与静态成员变量类似,类里面同样可以定义静态成员函数。只需要在函数前加上关键字static就可以。如静态成员函数也是类的一部分,而不是对象的一部分。所有这些对象的静态数据成员都共享这一块静态存储空间。

附加:

面向对象的static关键字

静态数据成员有以下特点:

(1)静态数据成员要在类外定义,此时不能再带上static的关键字。

(2)静态数据成员和普通数据成员一样遵从public,protected,private访问规则;

(3)private,protected 的static成员虽然可以在类外初始化,但是不能在类外被访问。

(4)静态成员为所有类对象所共享

(5)类的静态数据成员有两种访问形式:

<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>

如果静态数据成员的访问权限为public时,可在程序中按上述格式来引用静态数据成员静态成员函数,关于静态成员函数,可以总结为以下几点:

出现在类体外的函数定义不能指定关键字static;

(1) 静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

(2) 非静态成员函数可以任意地访问静态成员函数和静态数据成员;

(3) 静态成员函数不能访问非静态成员函数和非静态数据成员;

(4) 由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;

(5) 调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:

<类名>::<静态成员函数名>(参数)调用类的静态成员函数

4、线程和进程的联系和区别?

(1)进程包含线程,一个进程里可以有一个或多个线程;

(2)进程和线程都是为了处理并发编程这样的场景,但是进程创建和释放的时候效率低,相比之下,线程更轻量,创建和释放效率更好;

(3)操作系统创建进程是给进程分配资源,进程是操作分配资源的基本单位,操作系统创建的线程是在CPU上调度执行,线程是操作系统调度执行的基本单位;

(4)进程具有独立性,每个进程有各自的虚拟地址空间,一个进程挂了不会影响其他进程,同一个进程的多个线程共用同一个内存空间,一个线程挂了很可能会影响其他的线程,甚至导致整个进程崩溃。

5、C和C++的区别是什么?

C是结构化语言,其重点是算法和数据结构,C++在C的基础上增加类。C程序考虑的是如何通过一个过程,对输入进行运算处理得到输出,而对于C++而言,首先考虑的是如何构造一个对象模型,使得该模型与之对应的问题域契合,就可以通过获取对象的状态信息得到输出或实现过程控制。

6、const的用途是什么?

const用来定义只读变量,也就是常量。

const修饰函数的参数和函数的返回值。

const修饰函数的定义体,这里的函数是类的成员函数,被const修饰的成员函数代表不修改成员变量的值。

7、数组和链表有什么区别?

(1)在存储形式方面,数组是一块连续的空间,声明时就要确定长度;链表是一块可以不连续的动态空间,长度可以改变,每个结点都要保存相邻结点的指针。

(2)在数据查找方面,数组的线性查找速度快,查找操作直接使用偏移地址;链表需要按照顺序检索结点,效率较低。

(3)在数据的插入或删除方面,链表可以快速插入和删除结点,但数组需要大量的数据移动。

(4)在越界问题方面,链表不存在越界问题,数组存在越界问题。

(5)数组的优点:随机访问性强,查找速度快;数组的缺点:插入和删除效率低,可能浪费内存,内存空间要求高,必须有足够的连续空间,数组大小固定,不能动态拓展。链表的优点:插入删除速度快,内存利用率高,不会浪费内存,大小没有固定,拓展很灵活;链表的缺点:不能随机查找,必须从第一个开始遍历,查找效率低。

8、面向对象有什么特征?

面向对象具有封装性、继承和多态三大特征:

(1)封装性:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected, public)。

(2)继承性:广义的继承有三种实现形式:实现继承(使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。

(3)多态性:是将父类对象设置成为和一个或更多它的子对象相等的技术。用子类对象给父类对象赋值之后,父类对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。

9、在C++中,重载和重写的区别是什么?

重载指的是同一个访问区被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数的返回类型。

重写指的是派生类中存在重新定义的函数,它的函数名,参数列表,返回值类型,所有都必须和基类中被重写的参数一致。只有函数体不同,派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的挂不是关于不需要有virtual修饰。

10、解释一下封装、继承和多态?

封装是实现面向对象程序设计的第一步,将数据或函数等集合在一个个的单元(类)中。封装的意义就是保护或防止数据被无意破坏。

继承主要用来实现重用代码,节省开发时间,子类可以继承父类。

多态是指同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针来调用实现派生类中的方法。

11、常用的排序算法的优缺点和特点是什么?

常用的排序算法有选择、冒泡、快速、希尔、归并、堆排等。

(1)选择排序法的优点是移动数据的次数少,缺点是比较数据的次数多。

(2)冒泡排序法的优点是数据稳定,误差小,缺点是速度慢。

(3)快速排序是冒泡排序的一种改进,其优点是速度快,数据移动少,缺点是稳定性不足。

(4)希尔排序先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全体记录进行依次直接插入排序。其优点是速度快,数据移动少,缺点是不稳定。

(5)归并算法是一种分治法排序,该算法比较稳定,一般用于对总体无序但局部有序的数列。其优点是效率较高,稳定,缺点是比较占用内存。

(6)堆排序在直接选择排序的基础上利用了比较结果。因此它的优点是效率提高很大,缺点是对数据的有序性不敏感。

12、new和malloc的区别?

(1)new是C++中的操作符,malloc是C中的一个函数。

(2)new不止分配内存,而且会调用类的构造函数,同理delete调用类的析构函数,而malloc只分配内存,不会进行初始化类成员的工作,同样free也不会调用析构函数。

(3)内存泄露对于malloc或者new都可以检查出来,区别在于new可以指明是文件的哪一行,而malloc没有这些信息。

(4)new可以认为是malloc加构造函数的执行,new出来的指针是直接带类型信息的,而malloc返回的值都是void指针。

13、有没有用过STL库?常见的STL容器有哪些?算法用过哪几个?

STL包括两部分内容:容器和算法。容器,即存放数据的地方。比如array等。在STL中,容器分为两类:序列式容器和关联式容器。

序列式容器,其中的元素不一定有序,但都可以被排序。如:vector、list、deque、stack、queue、heap、priority_queue、slist;关联式容器,内部结构基本上是一颗平衡二叉树。所谓关联,指每个元素都有一个键值和一个实值,元素按照一定的规则存放。如:RB-tree、set、map、multiset、multimap、hashtable、hash_set、hash_map、hash_multiset、hash_multimap。

下面各选取一个作为说明:

vector:它是一个动态分配存储空间的容器。区别于C++中的array,array分配的空间是静态的,分配之后不能被改变,而vector会自动重分配(扩展)空间。

set:其内部元素会根据元素的键值自动被排序。区别于map,它的键值就是实值,而map可以同时拥有不同的键值和实值。

算法,如排序,复制等以及容器特定的算法。

迭代器是STL的精髓,将其描述为:迭代器提供了一种方法,使它能够按照顺序访问某个容器所含的各个元素,但无需暴露该容器的内部结构。它将容器和算法分开,好让这二者独立设计。

14、const的作用是什么?

(1)const修饰类的成员变量,表示成员常量,不能被修改。

(2)const修饰函数承诺在本函数内部不会修改类内的数据成员,不会调用其他非const成员函数。

(3)如果const构成函数重载,const对象只能调用const函数,非const对象优先调用非const函数。

(4)const函数只能调用const函数,非const函数可以调用const函数。

(5)类体外定义的const成员函数,在定义和声明外都需要const修饰符。

15、快速排序使用代码简单实现。

#include<iostream>

using namespace std;

int n,a[1000001];

void qsort(int l,int r)//应用二分思想

{

int mid=a[(l+r)/2];//中间数

int i=l,j=r;

do{

while(a[i]<mid) i++;//查找左半部分比中间数大的数

while(a[j]>mid) j--;//查找右半部分比中间数小的数

if(i<=j)//如果有一组不满足排序条件(左小右大)的数

{

swap(a[i],a[j]);//交换

i++;

j--;

}

}while(i<=j);//这里注意要有=

if(l<j) qsort(l,j);//递归搜索左半部分

if(i<r) qsort(i,r);//递归搜索右半部分

}

int main()

{

cin>>n;

for(int i=1;i<=n;i++) cin>>a[i];

qsort(1,n);

for(int i=1;i<=n;i++) cout<<a[i]<<" ";

}

16、构造函数初始化列表和直接在构造函数内初始化有什么区别?

在进入派生类的构造函数内的时候,基类的部分已经构造完成了,你没有使用成员初始化列表初始化基类,因此基类采用的是基类自己默认的构造函数初始化的,然后进入构造函数后,又使用基类的构造函数构造一次,说明基类部分构造了两次,肯定报错。在构造函数初始化赋值效率低,常数据成员的初始化必须在初始化列表里完成。

以下几种情况必须使用初始化列表去初始化类成员:

当初始化一个reference member时,即成员类型是引用。

当初始化一个const member时,即成员类型是常量。

当调用一个基类的constructor,而它拥有一组参数时。如果此时不使用列表初始化,那么就需要自己重载赋值运算符。

当调用一个类成员的constructor,而它拥有一组参数时。

若某个类成员没有定义无参构造函数,而定义了其它的构造函数,也必须使用初始化列表。

总之,为了标准化,建议使用列表初始化。不过小心一些陷阱:

因为类成员的初始化顺序不是按照初始化列表的顺序来的,而是按照类成员的声明顺序。

17、描述sizeof和strlen的区别。

(1)sizeof 是一个操作符,strlen 是库函数。

(2)sizeof 的参数可以是数据的类型,也可以是变量,而 strlen 只能以结尾为‘\0‘的字符串作参数。

(3)编译器在编译时就计算出了 sizeof 的结果。而 strlen 函数必须在运行时才能计算出来。并且 sizeof 计算的是数据类型占内存的大小,而 strlen 计算的是字符串实际的长度。

(4)数组做 sizeof 的参数不退化,传递给 strlen 就退化为指针了。

注意:有些是操作符看起来像是函数,而有些函数名看起来又像操作符,这类容易混淆的名称一定要加以区分,否则遇到数组名这类特殊数据类型作参数时就很容易出错。最容易混淆为函数的操作符就是 sizeof。

18、说明strcpy、sprintf和memcpy的区别。

(1) 操作对象不同,strcpy 的两个操作对象均为字符串,sprintf 的操作源对象可以是多种数据类型,目的操作对象是字符串,memcpy 的两个对象就是两个任意可操作的内存地址,并不限于何种数据类型。

(2) 执行效率不同,memcpy 最高,strcpy 次之,sprintf 的效率最低。

(3) 实现功能不同,strcpy 主要实现字符串变量间的拷贝,sprintf 主要实现其他数据类型格式到字符串的转化,memcpy 主要是内存块间的拷贝。

说明:strcpy、sprintf 与 memcpy 都可以实现拷贝的功能,但是针对的对象不同,根据实际需求,来选择合适的函数实现拷贝功能。

19、C++空类有哪些成员函数?

缺省构造函数、缺省拷贝构造函数、缺省析构函数、缺省赋值运算符、缺省取址运算符、缺省取地址运算符const。

this指针有哪些特性呢?

1)this是一个指针,它时时刻刻指向你这个实例本身。

2)this指针的类型类类型 *const

3)this指针并不是对象本身的一部分,不影响sizeof的结果

4)this指针的作用域在类成员函数的内部

5)只有在类的非静态成员函数中才可以使用,其它任何函数都不可以

20、简单谈一下对拷贝构造函数和赋值运算符的理解。

拷贝构造函数和赋值运算符重载有以下两个不同之处:

(1)拷贝构造函数生成新的类对象,而赋值运算符不能。

(2)由于拷贝构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验源对象是否和新建对象相同。而赋值运算符则需要这个操作,另外赋值运算中如果原来的对象中有内存分配要先把内存释放掉

注意:当有类中有指针类型的成员变量时,一定要重写拷贝构造函数和赋值运算符,不要使用默认的。

21、描述类成员函数的重写、重载和隐藏的区别。

(1)重写和重载主要有以下几点不同。

范围的区别:被重写的和重写的函数在两个类中,而重载和被重载的函数在同一个类中。

参数的区别:被重写函数和重写函数的参数列表一定相同,而被重载函数和重载函数的参数列表一定不同。

virtual的区别:重写的基类中被重写的函数必须要有virtual 修饰,而重载函数和被重载函数可以被virtual修饰,也可以没有。

(2)隐藏和重写、重载有以下几点不同。

与重载的范围不同:和重写一样,隐藏函数和被隐藏函数不在同一个类中。

参数的区别:隐藏函数和被隐藏的函数的参数列表可以相同,也可不同,但是函数名肯定要相同。当参数不相同时,无论基类中的参数是否被 virtual 修饰,基类的函数都是被隐藏,而不是被重写。

说明:虽然重载和覆盖都是实现多态的基础,但是两者实现的技术完全不相同,达到的目的也是完全不同的,覆盖是动态态绑定的多态,而重载是静态绑定的多态。

22、描述多态实现的原理。

编译器发现一个类中有虚函数,便会立即为此类生成虚函数表 vtable。虚函数表的各表项为指向对应虚函数的指针。编译器还会在此类中隐含插入一个指针 vptr(对 vc 编译器来说,它插在类的第一个位置上)指向虚函数表。调用此类的构造函数时,在类的构造函数中,编译器会隐含执行 vptr 与 vtable 的关联代码,将 vptr 指向对应的 vtable,将类与此类的 vtable 联系了起来。另外在调用类的构造函数时,指向基础类的指针此时已经变成指向具体的类的this指针,这样依靠此this指针即可得到正确的vtable。

如此才能真正与函数体进行连接,这就是动态联编,实现多态的基本原理。

注意:一定要区分虚函数,纯虚函数、虚拟继承的关系和区别。牢记虚函数实现原理,因为多态。

23、说明队列和栈的区别。

队列和栈都是线性存储结构,但是两者的插入和删除数据的操作不同,队列是“先进先出”,栈是“后进先出”。

注意:区别栈区和堆区。堆区的存取是“顺序随意”,而栈区是“后进先出”。栈由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。堆一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。

24、typedef和define有什么区别?

(1)用法不同:typedef 用来定义一种数据类型的别名,增强程序的可读性。define 主要用来定义常量,以及书写复杂使用频繁的宏。

(2)执行时间不同:typedef 是编译过程的一部分,有类型检查的功能。define 是宏定义,是预编译的部分,其发生在编译之前,只是简单的进行字符串的替换,不进行类型的检查。

(3)作用域不同:typedef 有作用域限定。define 不受作用域约束,只要是在 define 声明后的引用都是正确的。

(4)对指针的操作不同:typedef 和 define 定义的指针时有很大的区别。

注意:typedef 定义是语句,因为句尾要加上分号。而 define 不是语句,千万不能在句尾加分号。

25、简述指针常量和常量指针的区别。

指针常量是指定义了一个指针,这个指针的值只能在定义时初始化,其他地方不能改变。常量指针是指定义了一个指针,这个指针指向一个只读的对象,不能通过常量指针来改变这个对象的值。

指针常量强调的是指针的不可改变性,而常量指针强调的是指针对其所指对象的不可改变性。

注意:无论是指针常量还是常量指针,其最大的用途就是作为函数的形式参数,保证实参在被调用函数中的不可改变特性。

26、如何避免“野指针“?

“野指针”产生原因及解决办法如下:

(1)指针变量声明时没有被初始化。解决办法:指针声明时初始化,可以是具体的地址值,也可让它指向 NULL。

(2)指针p被 free 或者 delete 之后,没有置为 NULL。解决办法:指针指向的内存空间被释放后指针应该指向 NULL。

(3)指针操作超越了变量的作用范围。解决办法:在变量的作用域结束前释放掉变量的地址空间并且让指针指向 NULL。

注意:“野指针”的解决方法也是编程规范的基本原则,平时使用指针时一定要避免产生“野指针”,在使用指针前一定要检验指针的合法性。

27、解释下常引用的作用。

常引用的引入主要是为了避免使用变量的引用时,在不知情的情况下改变变量的值。常引用主要用于定义一个普通变量的只读属性的别名、作为函数的传入形参,避免实参在调用函数中被意外的改变。

说明:很多情况下,需要用常引用做形参,被引用对象等效于常对象,不能在函数中改变实参的值,这样的好处是有较高的易读性和较小的出错率。

28、构造函数能否为虚函数?

构造函数不能是虚函数。而且不能在构造函数中调用虚函数,因为那样实际执行的是父类的对应函数,因为自己还没有构造好。析构函数可以是虚函数,而且,在一个复杂类结构中,这往往是必须的。

析构函数也可以是纯虚函数,但纯虚析构函数必须有定义体,因为析构函数的调用是在子类中隐含的。

说明:虚函数的动态绑定特性是实现重载的关键技术,动态绑定根据实际的调用情况查询相应类的虚函数表,调用相应的虚函数。

29、简述C++程序编译的内存分配情况。

C、C++中内存分配方式可以分为三种:

(1)从静态存储区域分配:

内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易出错,因为有系统会善后。例如全局变量,static 变量等。

(2)在栈上分配:

在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

(3)从堆上分配:

即动态内存分配。程序在运行的时候用 malloc 或 new 申请任意大小的内存,程序员自己负责在何时用 free 或 delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活。如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,另外频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

一个C、C++程序编译时内存分为 5 大存储区:堆区、栈区、全局区、文字常量区、程序代码区。

30、一个指针可以是volatile吗?

可以,因为指针和普通变量一样,有时也有变化程序的不可控性。常见例:子中断服务子程序修改一个指向一个 buffer 的指针时,必须用 volatile 来修饰这个指针。

指针是一种普通的变量,从访问上没有什么不同于其他变量的特性。其保存的数值是个整型数据,和整型变量不同的是,这个整型数据指向的是一段内存地址。

31、变量的声明和定义有什么区别?

为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方声明,但是只在一个地方定义。加入 extern 修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。说明:很多时候一个变量,只是声明不分配内存空间,直到具体使用时才初始化,分配内存空间,如外部变量。

33、结构体struct内存对齐的三大规则

(1)对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍;

(2)结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍;

(3)如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型。

34、联合体union内存对齐的2大原则

(1)找到占用字节最多的成员;

(2)union的字节数必须是占用字节最多的成员的字节的倍数,而且需要能够容纳其他的成员

35、位域(大疆笔试题)

C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。一个位段必须存储在同一存储单元中,不能跨两个单元。如果第一个单元空间不能容纳下一个位段,则该空间不用,而从下一个单元起存放该位段。

(1)位段声明和结构体类似

(2)位段的成员必须是int、unsigned int、signed int

(3)位段的成员名后边有一个冒号和一个数字

36、attribute((packed))取消对齐

GNU C的一大特色就是__attribute__机制。__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。

__attribute__书写特征是:__attribute__前后都有两个下划线,并且后面会紧跟一对括弧,括弧里面是相应的__attribute__参数。

跨平台通信时用到。不同平台内存对齐方式不同。如果使用结构体进行平台间的通信,会有问题。例如,发送消息的平台上,结构体为24字节,接受消息的平台上,此结构体为32字节(只是随便举个例子),那么每个变量对应的值就不对了。不同框架的处理器对齐方式会有不同,这个时候不指定对齐的话,会产生错误结果

37、inline内联函数

在C语言中,如果一些函数被频繁调用,不断地有函数入栈,即函数栈,会造成栈空间或栈内存的大量消耗。为了解决这个问题,特别的引入了inline修饰符,表示为内联函数。

大多数的机器上,调用函数都要做很多工作:调用前要先保存寄存器,并在返回时恢复,复制实参,程序还必须转向一个新位置执行。C++中支持内联函数,其目的是为了提高函数的执行效率,用关键字 inline 放在函数定义(注意是定义而非声明)的前面即可将函数指定为内联函数,内联函数通常就是将它在程序中的每个调用点上“内联地”展开。

内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。

#嵌入式八股##通信硬件人笔面经互助#
嵌入式学习免费专栏 文章被收录于专栏

分享嵌入式软件开发相关资料,专栏永久免费,嵌入式学习技术交流

全部评论

相关推荐

10 73 评论
分享
牛客网
牛客企业服务