http://emb.hqyj.com/jobs/
1 结构体
结构体的字节对齐
struct A { char a; int b; short c; };
首先计算每个成员变量的对齐方式:
- a:1字节
- b:4字节
- c:2字节
所以最大字节对齐为MAX(1,4,2)= 4,所以整个机构体就是4字节对齐。
前一个结构体成员分配空间后,然后对齐(对齐方式 = 下一个结构体成员的对齐方式),如:a要满足b的4字节对齐,所以要空3个字节。
最后一个成员要满足整个结构体的对齐方式,所以成员c后面要空2字节。
结构体的柔性数组
struct A { char a; int b; short c; char d[0];//柔性数组 };
c++的struct 和 c的struct区别
1.c++中,class和struct的区别:
- 成员访问权限->class的成员访问权限为private,而struct的成员访问权限为public
- 默认的继承方式->class的默认继承方式为private,而struct的默认继承方式为public
2.struct在C和C++之间的区别
- c中,struct是用户自定义数据类型,而c++中,struct是抽象数据类型,支持成员定义函数;
- c中的struct是没有权限设置的,但是在c++中,给strcut添加了权限设置,增加了访问权限;
- c中的struct只是变量的聚合体,可以封装数据,但是不可以隐藏,不可以定义函数成员;但是C++中的struct可以定义函数成员
下面结构体大小
struct A{
char a;
short b;
char c;
int d;
};
class A g;
cout<<sizeof(g); //12
2 共用体
共用体也存在字节对齐。
3 枚举
只能给枚举变量 赋 枚举值。
声明枚举变量三种方法
1、先声明枚举类型后定义枚举类型变量enum WeekdayType { sun,mou,tue,wed,thu,fri,sat }; enum WeekdayType today,yesterday,tomorrow;
2、声明枚举类型的同时定义枚举类型变量
enum WeekdayType { sun,mou,tue,wed,thu,fri,sat }today,yesterday,tomorrow;
3、直接定义枚举类型变量
enum { sun,mou,tue,wed,thu,fri,sat }today,yesterday,tomorrow;
c语言中只有enum可以实现真正的常量,而const只是限制符。
4 变量问题
局部变量能否和全局变量重名?
答:能,局部会屏蔽全局。要用全局变量,需要使用如"::A" ;局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。
如何引用一个已经定义过的全局变量?
答:extern 可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个编写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
答:可以,在不同的C文件中以static形式来声明同名全局变量。
可以在不同的C文件中extern声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错.
5 函数
C语言源程序的基本单位是:函数。
杂项===============================
堆和栈的区别
堆栈空间分配
栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表
生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
①栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。
②堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
栈:是桶型结构。堆:是树型结构
堆栈:什么是堆栈?又该怎么理解呢?
注意:其实堆栈本身就是栈,只是换了个抽象的名字。
程序编译的过程?
主要经过四个过程:预处理、编译、汇编和链接
1). 使用的时候要记得指针的长度.
2). malloc的时候得确定在那里free.
3). 对指针赋值的时候应该注意被赋值指针需要不需要释放.
4). 动态分配内存的指针最好不要再次赋值.
5). 在C++中应该优先考虑使用智能指针.
i++和++i的区别是什么?
int main()
{
int i = 1;
printf("%d,%d\n", ++i, ++i); //3,3
printf("%d,%d\n", ++i, i++); //5,3
printf("%d,%d\n", i++, i++); //6,5
printf("%d,%d\n", i++, ++i); //8,9
system("pause");
return 0;
}
i++是先传参,再计算。
++i是先让printf的计算完后,再传参。
三目运算符
在C中三目运算符(? :)的结果仅仅可以作为右值,比如如下的做法在C编译器下是会报错的,但是C++中却是可以是通过的。这个进步就是通过引用来实现的,因为下面的三目运算符的返回结果是一个引用,然后对引用进行赋值是允许的。
int main(void)
{
int a = 8;
int b = 6;
(a>b ? a : b) = 88;
cout<<a; //output 88
return 0;
}
下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的错误。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf(" Area = %f", area);
return area;
}
1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。
3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
4). 与第三点一脉相承,printf()经常有重入和性能上的问题。
如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。
不能传参数 不能有返回值 不能有打印语句 不应该使用浮点运算
堆内存碎片产生原因,及处理方法
内存碎片分为:内部碎片和外部碎片。
内部碎片
- 内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间;
- 内部碎片是处于区域内部或页面内部的存储块。占有这些区域或页面的进程并不使用这个存储块。而在进程占有这块存储块时,系统无法利用它。直到进程释放它,或进程结束时,系统才有可能利用这个存储块。(有点占着茅坑不拉屎的意思)
外部碎片
- 内存块太小了无法分配给申请内存空间的新进程的内存空闲区域。
- 由于它们的地址不连续或其他原因,使得系统无法满足当前申请。
主要有两点,一是申请的内存地址是跟页或段有关系,必须是倍数关系,一般是4,8,16的倍数。二是申请的内存空间必须是连续的,无法跨地址。所以就会产生碎片。
处理办法,没有绝对的好办法。
- 结构体的对齐;
- 用完内存及时释放;
- 或者是使用内存池,就可以按自己需要来管理内存,比如对于申请小片的内存就不要使用新的内存快,而是使用之前用过已经释放的,这样之后如果要申请大空间那就可以申请也会减少碎片。
参考:
https://blog.youkuaiyun.com/kuweicai/article/details/82779648
重要: