1.关键字Volatile的作用是什么?
首先Volatile的字面意思是易变的,Volatile关键字一般用于寄存器变量,起到防止编译器优化作用
因为寄存器是会经常做存取操作,而对于经常做存取操作的变量来说,编译器一般
会对其进行优化,举个例子
XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;
编译器优化过后就只有XBYTE[2]=0x58这一条,如果在变量XBYTE前添加Volatile关键字
就会防止编译器进行优化,从而保证四条操作语句得到编译
[1.1]关键字register的作用是什么?
首先register关键字的字面意思是寄存器,所以它的作用显而易见是告诉编译器将一个变量放入寄存器中存放,当该变量被大量的调用时可以提高效率,因为寄存器操作相对于编译器自行进行寻址分配是更快更直接的。但使用register 关键字修饰并不代表该变量就绝对存放在寄存器中,当register变量定义的数量大于电脑本身寄存器的数量时就可能失败。
使用register 变量要注意几个点:
a)由于时寄存器变量,故没有办法对其进行取地址,
b)寄存器只能在一个块内使用(局部),而不能在全局范围内(在主外部)使用。
c)寄存器类型必须是cpu所接收的数据类型
2.union和struct的区别,以及如何计算字节大小?
老生常谈的问题,首先要明确的一点是:
1.union是取成员的最大值,即所有成员公用一块地址空间,struct是所有成员的字节总和
2.union和struct都有字节对齐问题
ep:
typedef union
{
double i;
int k[5];
char c;
}DATE;
typedef struct data{40
int cat; 4
DATE cow;24
double dog;8
}too;
DATE max;
printf ("%d", sizeof(too)+sizeof(max));
分析:union是所有成员公用一块地址空间,所以取占空间最大的int k[5],再看最大的数据类型找对齐,最大的是double,在32位机器上,double占8字节,所以是8字节对齐,故同时满足int k[5]至少需要24字节的空间,所以union是24字节。在struct中 4+24+8 = 36 再找最大的数据类型找对齐,最大的同样是double 8字节,所以是8字节对齐同时要满足36字节的空间大小则至少需要8*5 = 40的字节大小。
故输出 24+40 = 64
3.内存分配问题?
内存分配大致分为三类:栈上内存、堆上内存、静态存储区内存
a.静态存储区分配:主要是全局变量、静态变量的分配,该区的生命周期一般比较长,程序的运行期间一直存在
b.栈上内存:一般需要压栈的都是局部变量,在函数结束时自动释放
c.堆上内存: 一般由程序员手动操作进行释放
4.内存泄漏/内存溢出问题?
先说一下我对泄漏的理解,就是当一个变量或一块地址空间没有被系统释放的时候,就会造成内存泄漏,当内存泄漏堆积到一定程度就会造成OOM(out of memory)内存溢出
比方说你定义了一个指针并给其分配了地址空间,但你并没有释放,那么当程序结束的时候你就会造成内存泄漏。
内存溢出就是指当系统申请内存空间的时候不能提供足够的内存空间供其使用、
常见的内存泄漏情况:
1.new delete/malloc free未成对出现
2.局部申请的内存空间没有在局部进行释放
3.没有将基类的析构函数定义为虚函数,当基类的指针指向子类时,delete该对象时,不会调用子类的析构函数
二者的关系:
内存溢出会抛出异常,内存泄露不会抛出异常,大多数时候程序看起来是正常运行的
5.如何判断大小端?说出几种方法。
a)通过union联合体来判断
ep:
union{
int a;
char b;
}c;
c.a = 1;
if(c.b == 1)//小端存储
else //大端
b)通过指针进行判断
ep:
int a = 0x12345678;
unsigned char *p = &a;
if(*p == 78)//小端
else//大端
c)强转
int a = 0x12345661;
if((char)a == 'a')//小端
else 大端
5.函数的重载/隐藏/覆盖?
成员函数重载(overload)
是指函数名相同,参数不同(个数、类型),特征如下:
A、相同的范围(在同一个类中)
B、函数名字相同
C、参数不同
D、virtual 关键字可有可无a
E、返回值可以不同
成员函数覆盖(override,也称重写)
是指派生类重新定义基类的虚函数,特征如下:
A、不同的作用域(分别位于派生类与基类)
B、函数名字相同
C、参数相同
D、基类函数必须有virtual关键字,不能有static
E、返回值相同
F、重写函数的权限访问限定符可以不同
成员函数隐藏(也称重定义)
A、不在同一个作用域(分别位于派生类与基类)
B、函数名字相同
C、返回值可以不同
D、根据参数来区分:
参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意与重载的区别)
参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意与覆盖的区别)
6.类的静态
1)类的静态成员变量
a.在创建成员变量的时候加static关键字就被定义为静态成员变量,静态成员变量是类内声明类外定义。
b.静态成员变量只分配一次内存空间,存储在全局区,供所有对象使用
c.静态成员变量在定义时分配内存,所以不能在类内定义,只能类内声明。
d.静态成员变量只初始化一次。
2)类的静态成员函数
A. 出现在类体外的函数定义不能指定关键字static;
B. 静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
C. 非静态成员函数可以任意地访问静态成员函数和静态数据成员;
D. 静态成员函数不能访问非静态成员函数和非静态数据成员;
E. 由于没有this指针的额外开销,因此静态成员函数与类的成员函数相比速度上会有少许的增长;
7.虚析构函数
为什么基类需要虚析构函数?
在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生。
若B是A的子类: A *a=new B;
delete a;
如果A的析构函数是non-vartual,则只会调用A的析构函数,这样B的资源没有释放,就会有内存泄露;如果A的析构函数是vartual,则只会先调用A的析构函数,再调用B的析构函数。所以要将父类的析构函数定义为虚析构函数,这样就会防止内存泄漏,将二者的空间都释放掉
8.比较new、delete、malloc、free的区别?
都可用于申请动态内存和释放内存
1、new/delete是C++的操作符,而malloc/free是C中的函数。
2、new做两件事,一是分配内存,二是调用类的构造函数;同样,
delete会调用类的析构函数和释放内存。而malloc和free只是分配和释放内存。
3、new建立的是一个对象,而malloc分配的是一块内存;
new建立的对象可以用成员函数访问,不要直接访问它的地址空间;
malloc分配的是一块内存区域,用指针访问,可以在里面移动指针;new出来的指针是带有类型信 息的,而malloc返回的是void指针。
4、new/delete是保留字,不需要头文件支持;malloc/free需要头文件库函数支持。