目录
C++/嵌入式八股学习-day3
C/C++
使用指针传递大容量参数
在C语言中,当函数参数较大时,为了避免传递复制数据导致内存开销较大,可以使用指针来传递参数。下面是使用指针传递大容量参数的示例:
#include <stdio.h>
#include <stdlib.h>
void func(int *array, int size) { // 定义函数,传递指针和数组大小
int i;
for (i = 0; i < size; i++) {
printf("%d ", array[i]); // 输出数组中的元素
}
printf("\n");
}
int main() {
int size = 1000000; // 声明数组大小
int *array = (int *)malloc(size * sizeof(int)); // 动态分配内存,创建数组
// 初始化数组
int i;
for (i = 0; i < size; i++) {
array[i] = i;
}
func(array, size); // 通过指针传递参数
free(array); // 释放内存
return 0;
}
在上述代码中,我们首先使用malloc()动态分配了一个包含1000000个整型元素的数组。然后在main()函数中初始化数组,并通过指针调用func()函数来访问数组中的元素。在func()函数中,我们使用了指针*array来访问数组中的元素,使用size参数指定了数组的大小。
函数中的形参定义的是一个int 型指针,那么传入的就需要是一个地址,可以是数组名,也就是数组的首地址,可以是对一个数据取地址&a,然后函数内使用就是array[1]或*(array+1),或 *a
需要注意的是,在使用指针传递参数时,需要确保指针指向的内存区域是有效的,并且在使用完毕后需要释放内存,以免造成内存泄漏。
如何禁止程序自动生成拷贝构造函数?
可以通过将拷贝构造函数声明为私有成员函数来禁止程序自动生成拷贝构造函数,具体的做法是:
class MyClass {
public:
// 其他构造函数的声明
private:
// 禁止拷贝构造函数自动生成
MyClass(const MyClass&);
};
通过将拷贝构造函数声明为私有成员函数,可以防止程序在需要拷贝对象时自动调用拷贝构造函数。如果程序中需要拷贝该类的对象(类的成员函数和friend函数还是可以调用private函数,如果这个private函数只声明不定义,则会产生一个连接错误),编译器会在编译时报错。
需要注意的是,将拷贝构造函数声明为私有成员函数会影响该类对象的拷贝行为,可能会导致一些问题,因此应该慎重使用。如果确实需要禁止拷贝行为,建议使用 C++11 中引入的 =delete 关键字来禁止拷贝构造函数,具体做法如下:
class MyClass {
public:
// 其他构造函数的声明
// 禁止拷贝构造函数
MyClass(const MyClass&) = delete;
};
这种方式可以在编译时直接阻止程序调用拷贝构造函数,避免了由于访问限制导致的问题。
final和override关键字
1.final关键字
禁止虚函数被重写(最终虚函数)
禁止类被继承(最终类)
需要注意的是,只有虚函数才能使用final关键字
2.override关键字
用于表示子类的函数就是重写了父类的同名函数。
override
并不会影响程序的执行结果,仅仅是作用于编译阶段,用于检查子类是否真的重写父类函数
需要注意的是,只有虚函数才能使用override关键字
C++类内可以定义引用数据成员吗?
可以,引用数据成员是一个别名,它必须在定义时初始化,并且不能被重新赋值为另一个对象。必须通过成员函数初始化列表初始化。
例如:
csharpCopy codeclass MyClass {
public:
MyClass(int& r) : ref(r) {}
private:
int& ref;
};
在上面的示例中,MyClass 类包含一个整数类型的引用数据成员 ref,该引用必须在构造函数初始化列表中进行初始化。
需要注意的是,引用数据成员的生命周期必须长于它所引用的对象的生命周期,否则可能会出现悬垂引用的问题。因此,通常情况下应该避免在类中定义指向局部变量的引用数据成员。
此外,还需要注意,引用数据成员不能在类中声明为静态成员,因为引用必须与某个对象关联才有意义,而静态成员是类级别的,不与任何对象相关联。
auto关键字
关键字auto在C和C++编程语言中用于声明自动变量,它通常用于在函数内部声明变量,使得变量的存储期限与函数调用的生命周期相同。具体来说,使用auto关键字声明的变量会在函数调用结束后自动被销毁,不会占用内存空间。其实普通局部变量就是自动局部变量,只是省略了auto这一关键字。
在C++11标准中,auto关键字还被用于进行类型推断,可以根据变量的初始化表达式自动推断变量的类型,这种用法也被称为“自动类型推断”。例如:
auto i = 42; // 推断 i 的类型为 int
auto d = 3.14; // 推断 d 的类型为 double
auto s = "hello"; // 推断 s 的类型为 const char*
在这种情况下,编译器会根据初始化表达式的类型自动推断变量的类型,可以简化代码,提高可读性和可维护性。
成员函数里memset(this,0,sizeof(*this))会发生什么
有时候类里面定义了很多int,char,struct等c语言里的那些类型的变量,习惯在构造函数中将它们初始化为0,但是一句句的写太麻烦,所以直接就在成员函数中调用 memset(this, 0, sizeof(* this)) 会将该对象的内存空间全部清零。这样做会将对象的所有成员变量都初始化为 0,包括基本类型和自定义类型的成员变量,也包括指针类型的成员变量(指针类型的成员变量将被设置为 NULL)。
在一些情况下,可以使用 memset 来对对象的内存空间进行清零,比如在对象创建之后需要对其进行初始化,或者在将对象的内存空间释放之前需要将其清零以保护数据安全等。但是,如果对象的成员变量包含了指针类型或者虚函数等复杂类型,使用 memset 可能会导致不可预测的问题,因此需要谨慎使用。如果需要对对象进行初始化,应该考虑使用构造函数,而不是使用 memset。
ARM
SPIz总线的工作频率
SPI是一种事实标准,由Motorola开发,并没有一个官方标准。已知的有的器件SPI已达到50Mbps。具体到产品中SPI的速率主要看主从器件SPI控制器的性能限制。
SPI最大传输速率受以下几个条件影响:
1)SPI的最大时钟频率;
2)CPU处理SPI数据的能力;
3)输出端驱动能力(PCB所允许的最大信号传输速率);
ARM内部传输数据的总线有哪些?
ARM处理器内部主要有以下几种总线:
数据总线(Data bus):数据总线用于在CPU、寄存器、存储器等内部组件之间传输数据。在32位ARM处理器中,数据总线宽度为32位,因此能够传输32位数据。
地址总线(Address bus):地址总线用于指示内存中的特定位置。在32位ARM处理器中,地址总线宽度为32位,能够寻址4GB的内存空间。
控制总线(Control bus):控制总线用于传输控制信号,包括读写信号、片选信号、时序信号等,用于控制内部组件的操作。控制总线不是单独的总线,而是由多条信号线组成的。
中断总线(Interrupt bus):中断总线用于在不同的内部组件之间传输中断请求和中断响应信号,以实现中断处理功能。
IIC时钟拉伸
在IIC通信中,主设备决定了时钟速度。因为时钟脉冲信号是由主设备显式发出的。但是,当从设备没办法跟上主设备的速度时,从设备需要一种机制来请求主设备慢一点,这种机制称为时钟拉伸。而基于IIC结构的特殊性,这种机制得到实现。当从设备需要降低传输的速度的时候,它可以按下时钟线,逼迫主设备进入等待状态,直到从设备释放时钟线,通信才继续。
应用编程和网络编程
进程对信号的响应
-
忽略信号:当进程对某个信号进行忽略处理时,这个信号将被自动忽略,进程不会做出任何响应。可以通过signal()函数或者sigaction()函数来设置信号的处理方式为忽略。
-
捕获信号:当进程对某个信号进行捕获处理时,当该信号发生时,进程会执行一个特定的处理函数,该函数被称为信号处理函数。可以通过signal()函数或者sigaction()函数来设置信号的处理方式为捕获,并指定信号处理函数。
-
默认信号处理方式:对于大多数信号,系统都有一个默认的处理方式。例如,当进程收到SIGTERM信号时,系统默认会终止进程。当进程收到SIGINT信号时,系统默认会中断进程。如果进程没有对信号进行处理,系统将使用默认的处理方式。
驱动
请简述主设备号和次设备号的用途。
主设备号:主设备号标识设备对应的特定的驱动程序。虽然现代的linux内核允许多个驱动程序共享主设备号,但我们看待的大多数设备仍然按照“一个主设备对应一个驱动程序”的原则组织。 次设备号:次设备号由内核使用,用于确定由主设备号对应驱动程序中的各个设备。依赖于驱动程序的编写方式,我们可以通过次设备号获得一个指向内核设备的直接指针,也可将此设备号当作设备本地数组的索引。
可以用来指定这个驱动程序的哪个设备
可以给驱动程序任意使用,有驱动程序定义它的含义
可以主次设备结合,再用来找到其他设备