1.C++和C的区别,各自的优缺点?
区别在于:C++是C语言的扩展和发展,它在C的基础上引入了面向对象编程(OOP)的概念,并提供了更多的特性和功能。
1.语言特性:C++支持面向对象编程,包括封装、继承、多态等特性,而C只支持过程化编程。这使得C++更加灵活和功能丰富。
2.标准库:C++标准库比C标准库更加庞大且功能更加强大。C++标准库提供了大量的容器类、算法、字符串处理、输入输出和其他实用工具,使得开发人员能够更高效地编写和组织代码。
3.兼容性:C++是C的超集,意味着合法的C程序也是合法的C++程序。然而,C++引入了一些新的关键字和语法,因此不是所有C代码都能无修改地编译通过。
4.性能:由于C++引入了一些额外的特性,如虚函数机制和运行时类型识别(RTTI),相对于纯粹的C代码,C++程序可能会有轻微的性能损失。
2.下面一段代码,想在调用 f2(1)时打印 err1,调用f2(2)时打印 err4,但是代码中有一些问题,请做尽可能少的修改使之正确。
static int f1(const char *errstr, unsigned int flag)
{
int copy, index, len;
const static char **__err = {“err1”, “err2”, “err3”, “err4”};
if(flag & 0x10000)
copy = 1;
index = (flag & 0x300000) >> 20;
if(copy) {
len = flag & 0xF;
errstr = malloc(len);
if(errstr = NULL)
return -1;
strncpy(errstr, __err[index], sizeof(errstr));
} else
errstr = __err + index;
}
void f2(int c) {
char *err;
swtch(c) {
case 1:
if(f1(err, 0x110004) != -1)
printf(err);
case 2:
if(f1(err, 0x30000D) != -1)
printf(err);
}
}
static int f1(const char **errstr, unsigned int flag) //修改为双指针 { int copy, index, len; const static char *__err[] = {“err1”, “err2”, “err3”, “err4”}; //修改为指针数组 if(flag & 0x10000) copy = 1; index = (flag & 0x300000) >> 20; if(copy) { len = flag & 0xF; *errstr = malloc(len + 1);//赋值方式采用指针形式,且len+1 if(*errstr = NULL) return -1; strncpy(*errstr, __err[index], len); //此函数作用是将__err[index]的前len个字符复制到errstr中 (*errstr)[len] = ‘\0’;//这里是将errstr的第len个字符赋值为'\0' } else *errstr = __err[index]; //正确的赋值方式 return 0; } void f2(int c) { const char *err = NULL;//初始化指针变量 swtch(c) { case 1: if(f1(&err, 0x110004) != -1) printf("%s\n",err);//正确打印数据 break;//添加退出 case 2: if(f1(&err, 0x30000D) != -1) printf("%s\n",err); break; //添加退出 } }
3.全局变量可不可以定义在被多个.c 文件包含的头文件中?为什么?
不可以,因为在不同的.c文件中包含同一个同一个头文件的时候,会在每个.c文件中创建一个独立的编译单元。在每个编译单元中,全局变量会被当作独立的实体进行处理,即每个编译单元都会有自己的全局变量副本。
因此,如果将全局变量定义在被多个 .c 文件包含的头文件中,每个编译单元都会有自己的全局变量副本,这将导致多个副本的全局变量同时存在于程序中,相互独立且不同步。这可能会导致不可预料的行为和bug。
4.头文件中的 ifndef/define/endif 的作用?
在 C/C++ 的头文件中,可以使用
#ifndef
、#define
和#endif
组合来防止头文件的重复包含。
#ifndef
(如果未定义):检查宏是否已经定义,如果未定义,则继续编译下面的代码。这样可以确保这部分代码只会被编译一次,避免重复定义。
#define
:定义一个宏,将它设置为一个非零值,以表示头文件已经被包含。可以将宏定义为任何非零值,通常使用一个没有其他含义的标识符,比如_HEADER_NAME_H
。这个宏定义的作用是为了防止重复包含。
#endif
:结束条件编译块。示例
#ifndef _HEADER_NAME_H #define _HEADER_NAME_H // 在这里放置头文件的内容 #endif // _HEADER_NAME_H
5.看门狗有什么作用?
看门狗(Watchdog)是一种特殊的计时器硬件或软件机制,它用于监控系统的运行状态并在系统出现故障或死锁时采取相应的恢复措施。看门狗常见于嵌入式系统和实时系统中。
6.关键字static的作用是什么?
static它被用来控制变量的存储方式和可见性。
(1)static 修饰的静态局部变量只初始化一次,生命周期延长到程序运行结束以后才释放。
(2)static 修饰全局变量的时候,只能在本文件中访问,其他文件中无法访问,extern 外部声明也不可以。(访问领域)
(3)static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。
(4)static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。(存储空间)
(5)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。(生命周期)
(6)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。(数据安全)
7.编写程序,统计输入的一行字符串中字母,数字,空格和其他的字符的数目。
void InfoStrNum(string str,int len) { //字母,数字,空格和其他的字符的数目 int letter = 0, number = 0, space = 0, other = 0; for (int i = 0; i < len; i++) { if (str[i] >= 'a' && str[i] <= 'z' || str[i] >= 'A' && str[i] <= 'Z') //判断大小写字母 { letter++; } else if (str[i] >= '0' && str[i] <= '9') //统计数字 { number++; } else if (str[i] == ' ')//统计空格 { space++; } else { other++; } } cout << "字母:" << letter << endl; cout << "数字:" << number << endl; cout << "空格:" << space << endl; }
8.3个变量相互交换数据,a->b,b->c,c->a 使用c语言来写实际代码。
void SwapData() { int a = 10; int b = 20; int c = 30; int temp = 0; //数据交换 temp = a; a = b; b = c; c = temp; printf("a = %d,b = %d,c = %d\n",a,b,c); }
9.以下为windows NT下的32位C程序
char str[] = “12345678”;
char *p = “abcd”;
int n = 10;
printf(“%d %d %d\n”, sizeof(str), sizeof(p), sizeof(n));
sizeof(str)计算一维数组成员数量,结果为9(包括“\0“)。
sizeof(p)计算的是指针的大小,32位的系统指针的大小是4个字节,64位的系统指针的大小是8个字节。
sizeof(n)计算的是变量的大小,变量的大小是4个字节。
10.单片机地址总线宽度为13位,那么程序空间寻址范围为 8 k?
单片机地址总线宽度为13位,意味着地址总线能够表示的地址数为2的13次方,即2^13。程序空间寻址范围取决于单片机的体系结构和编程模型,通常情况下,程序空间寻址范围可以达到2^13个地址,即0到2^13-1。所以,程序空间寻址范围为8192个地址。
在单片机中,每个地址所对应的内存单元可以存储一个字节的数据。因此,程序空间寻址范围为8192字节,或者8192/1024=8K(千字节)。所以,程序空间寻址范围为8K。
11.假定有某单片机的移位指令RLC R规则为:R(n-1)->R(n), C->R(0), R(7)->C,其中R为寄存器,C为进位标志。假设寄存器var1=0x59,C=1,执行两次RLC var1后,var= (请用十六进制表示)。
初始状态:
var1 = 0x59 C = 1
第一次RLC
var1
:
- 将寄存器
var1
中的最高位(n-1位)的值保存到进位标志C
:C
= 0x1- 将进位标志
C
的值保存到最低位(0位):var1
= 0x58- 将其他位向左移动一位,最低位填入进位标志
C
的值:var1
= 0xB0此时的状态为:
var1 = 0xB0 C = 1
第二次RLC
var1
:
- 将寄存器
var1
中的最高位(n-1位)的值保存到进位标志C
:C
= 0x0- 将进位标志
C
的值保存到最低位(0位):var1
= 0xB0- 将其他位向左移动一位,最低位填入进位标志
C
的值:var1
= 0x60最终的状态为:
var1 = 0x60 C = 0
所以,执行两次RLC
var1
后,var1
的值为 0x60。
12.linux中,结束后台进程的命令是 。
ctrl+C,或者kill [选项] <PID>
13.linux中,某文件的权限是:drwxrw-r--,用数值形式表示该权限,则该八进制数为 764 ,该文件属性是 文件 (文件/目录),该文件对应的权限是 rwxrw-r-- 。
根据提供的权限信息:“drwxrw-r–”,将其转换为数值形式的权限为 764。这是因为每个权限位对应的数值如下:
r (读取权限) -> 4 w (写入权限) -> 2 x (执行权限) -> 1 - (无权限) -> 0
将每组权限转换为数值并按顺序排列,就可以得到相应的数值权限。在这个例子中,权限分组如下:
第一组(所有者权限):rwx -> 4 + 2 + 1 = 7 第二组(群组权限):rw- -> 4 + 2 + 0 = 6 第三组(其他用户权限):r-- -> 4 + 0 + 0 = 4
因此,八进制数形式的权限为 764。
接下来,根据提供的权限信息可以判断该文件属性为目录(以 “d” 开头,表示目录),对应的权限为 rwxrwxr–。
14.C语言中,结构struct和联合union这两种数据类型的差别是什么?
结构体(struct)是一种数据类型,它可以同时存储多个不同类型的成员,每个成员占用独立的内存空间,结构体的大小等于所有成员大小的总和。每个成员可以独立地被访问和操作。
联合体(union)也是一种数据类型,但它的所有成员共享同一块内存空间,也就是说,联合体中的所有成员使用同一段内存,成员的大小可能不同,但联合体的大小等于最大成员的大小。联合体只能同时存储一个成员的值,存储一个成员的值会覆盖之前存储的成员的值。
15.int (*p)(int ,int)中p表示什么?
int (*p)(int, int)
表示p
是一个指向接受两个int
类型参数并返回int
类型值的函数的指针。通过这个指针,你可以在程序中动态地指向不同的函数,并调用这些函数。
16.将int a的bit 3置为0,bit 6取反。
int a = 42; // 假设a的初始值是42 // 将第3位bit置为0 a &= ~(1 << 2); // 1左移2位,即位3,然后取反再按位与运算 // 第6位bit取反 a ^= (1 << 5); // 1左移5位,即位6,然后按位异或运算
17.一条i2c总线上能够同时挂多个设备吗?如果能,请说明条件,不能,请说明原因。
是的,一条I2C总线上可以同时连接多个设备。这是I2C总线的主要设计目标之一。
I2C(Inter-Integrated Circuit)总线是一种串行通信协议,使用两根信号线(SCL和SDA)实现设备之间的通信。它采用了主从架构,其中一个设备作为主设备(主控器),其他设备作为从设备。
在一条I2C总线上同时连接多个设备,需要满足以下条件:
I2C设备有唯一的地址:每个I2C设备必须有一个唯一的地址,以便主控器可以准确选择要与之通信的设备。
地址冲突避免:确保在总线上没有两个或多个设备具有相同的地址。为了避免地址冲突,你需要确保每个设备的地址是唯一的。
电气兼容性:I2C设备在电气特性上需要兼容。这包括在电压等级和信号传输速率方面的兼容性。确保所有设备都可以按照总线规范进行通信。
上拉电阻:I2C总线上的SCL和SDA信号线通常需要连接上拉电阻。这些上拉电阻会将信号线拉到正常电平,以确保信号的稳定性。确保所有设备连接到I2C总线上时都具有适当的上拉电阻。
总线容量和速率:I2C总线上连接的设备数量会影响总线的容量和通信速率。较多的设备数量可能导致总线负载增加,从而影响通信速率。确保总线上连接的设备数量与总线的负载容量和通信速率相匹配。
通过满足上述条件,就可以在一条I2C总线上同时挂载多个设备,实现它们之间的通信。
18.某个linux设备驱动中,驱动程序对某个事情的响应,存在两种机制。
A.事件被触发后,立即通过其ISR对事件作出响应。
B.事件被触发后,在其ISR中发送事件消息到消息队列,然后返回。另一个线程循环读
取消息队列中的消息,再根据消息的内容来作出响应。
以上两种响应机制,你认为各有什么优缺点?
A. 事件被触发后立即通过ISR对事件作出响应的机制的优缺点:
优点:
- 实时性高:由于事件被触发后立即响应,可以快速地处理事件并执行相应的操作。
- 简单性:整个响应过程只在ISR中完成,没有额外的线程和消息队列,简化了实现和调试过程。
缺点:
- 线程阻塞:在ISR中处理事件的过程中,可能需要进行一些耗时的操作,这样会导致ISR运行的时间过长,可能会阻塞其他重要的实时任务。
- 竞争条件:如果多个事件同时触发,可能会导致竞争条件的发生,需要额外的同步机制来保护共享资源的访问。
B. 事件被触发后在ISR中发送事件消息到消息队列,然后返回,另一个线程循环读取消息队列中的消息,再根据消息内容作出响应的机制的优缺点:
优点:
- 解耦性:通过使用消息队列,将事件的产生和响应解耦,使得事件的产生和处理逻辑分离,提高代码的可维护性和可扩展性。
- 异步性:ISR只负责将事件消息发送到队列,然后立即返回,不会阻塞其他任务的执行,提高了系统的并发性和响应能力。
- 安全性:通过使用消息队列作为数据交换的媒介,可以避免竞争条件和数据不一致的问题。
缺点:
- 延迟较高:由于事件的响应是在另一个线程中进行,需要循环读取消息队列,并根据消息的内容作出响应,因此响应的延迟会相对较高。
- 需要额外的线程和消息队列:为了实现消息的处理,需要另外创建一个线程,并维护一个消息队列,增加了系统资源的使用和管理的复杂性。
19.开发一个产品‘水耕机’,有如下的要求:
A、温度保持在 25℃ - 27℃
B、湿度保存 70%-80%
C、每天日照时间段为 9:00-17:00
D、低水位警告。
可以使用的传感器 :
1、 温度传感器 A (ADC 采样)
2、 湿度传感器 B (ADC 采样)
3、 水位传感器 C (高低电平,高为水位过低)
时间获取地方:
1、 时钟芯片(返回的秒数从 2000 年 1 月 1 日 00:00:00 开始到现在累加)
使用的器件:
1、 冷却泵
2、 加热管
3、 加湿器
4、 小风扇(用于干燥)
5、 蜂鸣器
6、 Led 灯光管
简单使用伪代码or流程图来描述描述整个代码的流程。
初始化传感器和设备 循环执行以下步骤: 获取当前时间和日期 获取温度传感器 A 的温度值 获取湿度传感器 B 的湿度值 获取水位传感器 C 的水位状态 如果当前时间在日照时间段内: 如果温度值小于25℃: 打开加热管 如果温度值大于27℃: 关闭加热管 如果湿度值小于70%: 打开加湿器 如果湿度值大于80%: 关闭加湿器 否则: 关闭加热管 关闭加湿器 如果水位状态为低水位警告: 闪烁 Led 灯光管 发出蜂鸣器警报 如果水位状态正常: 关闭蜂鸣器 如果水位状态为高水位: 关闭冷却泵 否则: 打开冷却泵 结束循环