各类新鲜小问题
本文章专门用于记录学习过程中遇到的感觉很新鲜的问题,以及一些冷知识
压栈顺序从右到左
刚听还觉得这有啥区别,实际上是表示这一行代码往栈里面放的顺序,不是栈开口朝左朝右,那当然没区别了
比如:
int p = 0;
printf("%d %d %d \n",p++,++p,p++);
结果是2 2 0,因为先放最右边的p++,放了个0,然后放++p,放了个2,然后放p++,放了个2,最后从栈弹出来,2 2 0
C语言从右向左保存临时数据的原因是:
为了支持可变长参数,以printf函数为例,,定义是这样的:
printf(const char* format,…)
右边的参数数量不定,如果讲fomat置于栈底,我们不知道偏移多少个单位才能到首个参数
最左边的参数存放的是参数个数,我们必须将其置于栈顶,才方便我们知道有几个
在main之前执行函数
可以通过constructor/destructor来指定函数执行顺序在main之前/之后,例如:
void before() __attribute__ ((constructor))
void after() __attribute__ ((destructor))
void before(){
printf("before");
}
void after(){
printf("after");
}
int main(){
printf("main");
return 0;
}
输出的结果就会是 before main after
内存申请与释放(底层实现)
new运算分两个阶段: (1 )调用:operator new
配置内存;(2)调用对象构造函数构造对象内容
delete运算分两个阶段: (1)调用对象析构函数; (2)调用::operator delete
释放内存
为了精密分工,STL allocator将两个阶段操作区分开来:内存配置有alloc:allocate()
负责, 内存释放由alloc:deallocate()
负责;对象构造由::construct()
负责, 对象析构由::destroy()
负责。
同时为了提升内存管理的效率,减少申请小内存造成的内存碎片问题,SGI STL采用了两级配置器,当分配的空间大小超过128B时,会使用第一级空间配置器; 当分配的空间大小小于128B时,将使用第二级空间配置器。第一级空间配置器直接使用malloc()、realloc()、 free()函数进行内存空间的分配和释放,而第二级空间配置器采用了内存池技术,通过空闲链表来管理内存。
模板类template
使用示例:构建一个通用的栈stack
template <typename T>
class Stack {
public:
Stack() : top(-1) {}
void push(T val) {
data[++top] = val;
}
T pop() {
return data[top--];
}
private:
T data[100];
int top;
};
由于使用了模板template <typename T>
,使得stack在应用的时候,可以随意指定内部元素类型,如stack<int>
、stack<double>
等等
构造函数不能声明为虚函数
因为虚函数表是在构造过程中创建的,你还没构造呢,哪来的虚函数表,也就没有所谓的虚构造函数,无法确定对象具体的对象。
多态时要虚析构
多态就是定义个父类指针,然后让他指向子类实现,比如:
class * Animal = class dog;
如果子类里面在堆区开内存了,delete只能调用到父类的析构函数,子类这块内存就没释放掉,内存泄漏了
多态还可以是子类覆盖父类同名函数,比如
class Animal{
virtual shit(){};
}
class Dog : public Animal{
virtual shit(){Dog shit};
}
这里面,当子类调用该函数时,就会调用到子类的该函数,子类这个函数也得写成虚函数,这和虚函数的实现方式有关:子类的虚函数指针指向子类的虚函数表中该虚函数所在位置,父类的虚函数指针指向父类的虚函数表中该虚函数所在位置,所以二者会调用到不同的实现,形成多态。
队列(Queue)与消息队列(Message Queue)
队列是FreeRTOS中的概念,其严格遵循队列的性质,只能从队首读,只能从队尾写,也可以按消息上传者的id来读
而消息队列是Linux中的概念,相对不那么严格,允许随机读取,也可以按类型读。
互斥锁和二进制信号量
本来以为二者完全相同,实际上还是略有不同的。
互斥锁可以
重定位
(1)Nand Flash:单位容量价格低、CPU不能直接访问、容易坏块;
(2)Nor Flash:单位容量价格高、CPU能直接访问、不易坏块、但是不能像内存一样写;
总结:代码必须保存在Flash、硬盘等掉电不丢失的存储介质中,但是代码又不能再这些ROM存储介质中直接运行,必须在RAM中运行,所以设备启动时必须要先将代码重定位到RAM中。
32/64位系统不同数据类型所占字节数和取值范围
字符串存在隐式类型转换
对于一个字符串“abc”
而言,如果将它赋值给指针,例如:
char* my_char=“abc”;
my_char[1]='+';
由于等号左边是一个指针,这时“abc”
会被隐式类型转换为char const*
,这时第二行的赋值操作就不被允许了,因为是const变量,会报错:Segmentation fault (core dumped)
class 和 struct
class 和 struct 最本质的区别 : class 是引用类型,它在堆中分配空间,栈中保存的只是引用;而 struct 是值类型,它在栈中分配空间。
C中的struct:
1、成员访问权限: 在C中,struct 中的所有成员都是公共的,没有默认的成员访问权限。这意味着你可以在任何地方访问和修改 struct 中的成员。
2、方法和函数: 在C中,struct 不能包含成员函数或方法。struct 通常只包含数据成员,而不包含与这些数据相关的行为。
3、继承: 在C中,struct 不支持继承的概念。你不能从一个 struct 派生出另一个 struct。
C++中的struct:
1、成员访问权限: 在C++中,struct 中的成员默认是公共的。这与C中的 struct 相似,但与C++中的 class 不同。
2、方法和函数: 在C++中,struct 可以包含成员函数,这使得它可以具有与数据成员相关的行为,就像 class 一样。
3、继承: 在C++中,struct 支持继承,就像 class 一样。你可以从一个 struct 派生出另一个 struct,并且可以使用访问修饰符来控制派生类对基类成员的访问权限。