八股1
Strlen 和sizeof读取同一个字符串,结果分别是多少?
Strlen
和 sizeof
是两个不同的函数,它们的行为不同,用于读取同一个字符串的结果也不同。
Strlen
是 C 语言中的一个函数,它用于计算字符串的长度,不包括末尾的空字符('\0')。
char str[] = "Hello, world!";
调用 Strlen(str)
将返回 13,调用 sizeof(str)
将返回 14,因为字符串占用了 14 个字节,包括末尾的空字符。
因此,如果使用 Strlen
和 sizeof
读取同一个字符串,它们的结果分别是字符串的长度(不包括末尾的空字符)和字符串所占用的字节数(包括末尾的空字符)。
在c语言中怎么防止头文件的重定义?
在C语言中,头文件可以重复引用,不会有任何编译错误产生。但是,如果在多个源文件中都包含了同一份头文件,而且这个头文件里面定义了一个宏、函数或变量,那么就可能会出现符号重定义的问题。
- 使用头文件包含 guards 宏
#ifndef MYHEADER_H
#define MYHEADER_H
/* header content */
#endif
- 在头文件中使用条件编译
#ifndef MYHEADER_H_DEFINED
#define MYHEADER_H_DEFINED
/* header content */
#endif
extern ‘c’的作用
extern "C" 的作用主要是为了能够正确实现C++代码调用其他C语言代码。由于C++支持函数重载,而C语言不支持,因此需要使用extern "C"来指定按C语言的方式编译函数,以便C++代码能够正确调用C语言代码。具体来说,使用extern "C"修饰的函数或类,其名称不会被C++编译器修改,而是按照指定的方式编译,从而保证了函数或类的名称与链接器期望的名称一致。
如果两个对象相同,那么在哈希表中如何操作?为什么?
如果两个对象相同,在哈希表中应该将它们映射到同一个哈希地址。这是因为哈希表的查找过程中,首先根据关键字的哈希值确定待查找元素可能所在的哈希槽,然后在该哈希槽中按照关键字值的大小进行线性查找,找到最终的元素位置。如果两个相同的元素被映射到了不同的哈希地址,那么在查找过程中需要进行多次查找,浪费了时间,降低了效率。
因此,当两个对象相同时,应该将它们映射到同一个哈希地址上。具体操作方法可以是:在哈希表中该哈希槽的位置上寻找空位,将其中一个对象插入该位置,另一个对象则直接覆盖原有的对象。这样,在后续的查找操作中,只需要在同一个哈希地址上进行一次查找就可以找到相同的对象,减少了查找次数,提高了效率。
C++和C相比有哪些优势
C++是C的扩展,它保留了C的所有特性并增加了一些新功能。C++和C相比,有以下优势:
- 继承和多态:C++支持继承和多态,这使得程序更加灵活和可扩展。
- 泛型编程:C++支持泛型编程,可以使用模板来编写通用的代码,可以方便地进行代码复用和扩展。
- 异常处理:C++支持异常处理,可以在出现异常情况下处理程序崩溃或不可预料的行为。
- 标准库:C++标准库包括大量的实用函数和数据结构,可以帮助开发人员快速地完成编程任务。
- 内存管理:C++具有自动内存管理机制,可以避免内存泄漏和内存溢出等问题。
- 类型安全:C++是一种类型安全的语言,可以避免类型错误和未定义行为等问题。
- 可移植性:C++具有很好的可移植性,可以在不同的平台上编译和运行代码。
总的来说,C++是一种功能强大的编程语言,适合开发各种类型的应用程序,包括操作系统、数据库、游戏、图像处理和嵌入式系统等。
C和C++相比有哪些优点
C和C++相比,有以下优点:
- 运行效率高:C的编译器通常会产生更高效的机器代码,因为C是一种更底层的编程语言,更接近硬件。
- 代码级移植性:由于C编译器产生的机器代码具有更好的可移植性,因此C代码可以在不同的平台上进行移植。
- 轻松实现跨平台性:由于C的代码级移植性较好,因此在不同的平台上运行时需要进行较少的调整。
- 适合底层系统开发:C更适合底层系统的开发,例如操作系统和嵌入式系统。
- 简单高效:C是一种简单而高效的语言,它的语法和语义都比较简单,易于学习和使用。
需要注意的是,C++包含了更多的特性和功能,因此在某些方面比C更强大和灵活。例如,C++支持面向对象编程,可以更好地处理复杂的应用程序。此外,C++还具有更好的类型检查和异常处理机制。但是,在某些情况下,C的优点使其成为更优的选择。
stm32如何进入中断?
在STM32中进入中断的方法如下:
- 首先进行初始化操作,例如开启总中断申请、设置优先级等。
- 在主循环中,手动开启中断请求。
- 在中断处理函数中执行相应的处理操作。
在STM32中,无论是何种类型的UART中断,都会进入同一个中断处理函数,因此在该函数中进行具体的判断和处理。
数据如何在单片机上计算?从哪里取出,放到哪里?
数据的计算是由单片机上的处理器执行的。数据从存储器(如存贮器RAM或只读存储器EEPROM)中被读取,然后传递给处理器进行计算。计算完成后,结果可以写回到存储器中。
单片机通常使用位变量定义和SFR(特殊功能寄存器)来存储和操作数据。位变量是用于存储单个位信息的变量,而SFR是用于存储数据和指令的特殊寄存器。这些变量和寄存器必须在CPU片内RAM的可位寻址空间中定义和分配。
当数据从外部设备(如传感器或输入设备)进入单片机时,它们通常需要通过输入/输出端口进行传输。同样地,计算结果也可以通过端口输出到其他设备(如显示器或电机控制器)。因此,数据的传输和存储在单片机的运算处理过程中至关重要。
static在函数内和函数外的作用
- 在函数内,static的作用是限制变量和函数的访问范围,将它们的作用域限定在定义它们的函数内部。这样,在其他函数中调用该函数时,无法访问该函数中定义的static变量和函数。
- 在函数外,static的作用是声明静态变量,将变量存储在静态存储区中,而不是栈内存中。静态变量只会在程序运行时存在一次,不会在每次函数调用时都创建,而是被多次重复使用。这有助于节省内存并提高程序的效率。同时,静态全局变量还可以被定义为const常量,从而无法被修改。
gcc编译过程 从.c到可执行文件
gcc编译过程从.c到可执行文件的基本步骤如下:
- 预处理(Preprocessing):gcc首先会搜索源代码文件和系统头文件,将所有宏替换和条件编译指令(如#ifdef、#ifndef等)替换为相应的代码,并根据#include指令将其他源代码文件包含到当前文件中。
- 编译(Compiling):gcc会将预处理后的代码进行语法分析,检查代码是否符合语法规则,并生成汇编代码。在编译过程中,gcc会使用自由的编译器,如GCC编译器。
- 汇编(Assembling):汇编过程是将汇编代码翻译成机器代码的过程。在汇编过程中,gcc会将汇编代码转换成机器指令,并将这些指令保存到一个目标文件中。
- 链接(Linking):链接过程是将目标文件转换成可执行文件的过程。在链接过程中,gcc会将目标文件和库文件(包括标准库文件和动态链接库文件)合并成一个可执行文件。如果源代码文件中调用了库函数,gcc会自动查找并链接相应的库文件。
总之,gcc编译过程从.c到可执行文件的基本步骤包括预处理、编译、汇编和链接四个阶段。在这个过程中,gcc会将源代码文件转换成可执行文件,并处理所有外部依赖项,以确保程序能够正确地运行。
UART的数据格式?如何保证在侦听UART时不会一直判断接收到0?
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种常见的串口通信协议,其数据传输格式包括起始符、数据、校验位和停止位。下面分别介绍它们的具体含义和作用:
- 起始符(Start Bit):表示一个数据的开始,通常使用一个低电平的位表示。
- 数据(Data Bit):表示实际传输的数据,通常使用5-8个二进制位表示。
- 校验位(Parity Bit):用于校验数据的正确性,通常使用1位,可以设置为奇校验(Odd Parity)或偶校验(Even Parity)。
- 停止位(Stop Bit):表示一个数据的结束,通常使用1-2个高电平的位表示。
在侦听UART数据时,如果不希望误判接收到0,可以在数据中添加一些填充字符,例如空格或制表符,以确保数据中的每个字节都有一个明显的起始和结束位置。
volatile关键字作用
- 保证变量写操作的可见性:当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
- 禁止指令重排序:保证变量前后代码的执行顺序。
stm32主频多少
stm32主频最高是168MHZ。F1系列基于Cortex-M3内核,主频为72MHz,F4系列基于Cortex-M4内核,主频最高为168MHz,集成了FPU功能。
嵌入式和pc软件有什么区别
嵌入式系统和PC机在软件开发上存在一些显著区别,以下是两者的一些主要区别:
- 硬件环境:嵌入式系统的硬件资源通常比PC机有限,因此在开发嵌入式系统软件时需要更加关注资源的使用和效率。而在PC机上,硬件资源更加丰富,软件开发过程更加自由。
- 调试:嵌入式系统的软件开发通常需要进行调试,以排除程序中的错误。嵌入式系统的调试过程可能比PC机更加复杂,因为可能需要通过串口或JTAG等方式进行调试。
- 可靠性:嵌入式系统的可靠性通常比PC机更高,因为嵌入式系统通常需要实时处理关键任务。为了提高嵌入式系统的可靠性,需要采取一些特殊的措施,如使用看门狗、硬件冗余等。
- 开发工具:嵌入式系统的软件开发需要使用特定的开发工具和环境,如Keil、IAR、MATLAB等。而PC机上的软件开发则可以使用多种开发工具和环境,如Visual Studio、Eclipse等。
- 通信:嵌入式系统和PC机之间的通信方式也存在差异。在嵌入式系统中,通常使用串口、SPI、I2C等通信方式。而在PC机中,则可以使用更多的通信方式,如USB、网络等。
总之,嵌入式系统和PC机在软件开发上存在许多差异,需要根据具体的硬件环境和需求选择合适的开发方法和工具。
cpu和输入输出设备是怎么通信的
CPU和输入输出设备是采用系统总线进行通信的。系统总线是连接计算机系统各个部件之间的一组通信线,负责连接各个部件并传输信息。通过系统总线,CPU可以将数据写入存储器或从存储器中读取数据。同时,系统总线也可以用来连接输入输出设备,实现信息交换。
在微型计算机中,CPU和输入输出设备之间的通信通常采用MMIO(内存映射输入输出)的方式。MMIO是一种将输入输出设备映射到内存地址的机制,使得CPU可以通过读写内存来与输入输出设备进行通信。在MMIO中,输入输出设备被当作内存一样对待,设备寄存器和数据存储器都被分配了内存地址。CPU通过读写这些地址来实现对输入输出设备的控制和数据传输。此外,CPU还可以通过中断机制及时响应输入输出设备的请求和事件。
define的#和##的区别
在define中,#和##都是预处理指令,用于定义宏。
#用来将参数转换为字符串,它将在宏的展开过程中将双引号添加到参数周围。例如,#define to_string(s) #s将在展开时将参数s转换为一个带有双引号的字符串。
##则用来连接前后两个参数,把它们变成一个字符串,不添加任何符号。例如,##define BY(x,y) x y将在展开时将参数x和y连接起来,形成一个字符串x y。
因此,#和##的区别在于它们在展开宏时的行为不同。
中断 能不能传递参数 能不能数学运算
中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。
中断函数不能进行参数传递,也没有返回值。在任何情况下都不能直接调用中断函数。中断函数使用浮点运算要保存浮点寄存器的状态。如果在中断函数中调用了其它函数,则被调用函数所使用的寄存器必须与中断函数相同,被调函数最好设置为可重入的。
中断可以执行数学运算,但是需要注意一些细节。在中断函数中执行数学运算时,需要确保使用的变量和资源已经被保护,以避免中断函数与主程序之间的冲突。此外,由于中断函数通常是在后台执行的,因此需要确保它们的执行时间尽可能短,以免影响系统的响应时间和性能。
在软件上,有中断号,中断向量表,中断函数,3者的关系是什么?
在软件上,中断号、中断向量表和中断函数三者密切相关,但它们并不是相同的概念。它们之间的关系如下:
- 中断号(Interrupt Number)
中断号是一个整数,用于标识硬件中断的类型。每个中断都有一个唯一的编号,这个编号称为中断号。中断号通常用于在计算机系统中定位相应的中断处理程序。 - 中断向量表(Interrupt Vector Table)
中断向量表是一个内存表,它包含每个中断号的入口地址。当一个中断被触发时,计算机系统将跳转到与该中断号相关的入口地址,开始执行中断处理程序。在大多数系统中,中断向量表是由操作系统或硬件管理。 - 中断函数(Interrupt Function)
中断函数是用于处理硬件中断的程序代码。当一个中断被触发时,计算机系统将跳转到与该中断号相关的中断函数,执行其中的指令来处理该中断。中断函数可以是一个由程序员编写的函数,也可以是由操作系统提供的默认中断处理程序。
总之,中断号用于标识中断类型,中断向量表用于定位中断处理程序的入口地址,中断函数用于处理硬件中断。它们共同构成了软件的中断处理机制,使得计算机系统能够及时响应各种硬件事件。
RISC和CISC的区别?
RISC(精简指令集计算机)和CISC(复杂指令集计算机)是当前CPU的两种架构。它们的区别在于不同的CPU设计理念和方法。
总体来说,RISC更注重指令执行速度,而CISC更注重指令功能和灵活性。具体区别如下:
- 指令系统:RISC指令系统相对简单,指令周期相对较短,而CISC指令系统相对复杂,指令周期相对较长。
- 存储器操作:RISC对存储器操作有限制,使控制简单化,而CISC机器的存储器操作指令多,操作直接。
- 程序:RISC汇编语言程序一般需要较大的内存空间,实现特殊功能时程序复杂,不易设计,而CISC汇编语言程序编程相对简单,科学计算及复杂操作的程序设计相对容易,效率较高。
- 中断:RISC机器在一条指令执行的适当地方可以响应中断,而CISC机器是在一条指令执行结束后响应中断。
- CPU:RISC CPU 包含有较少的单元电路,因而面积小、功耗低,而CISC CPU 包含有丰富的电路单元,因而功能强、面积大、功耗大。
- 用户使用:RISC微处理器结构简单,指令规整,性能容易把握,易学易用,而CISC微处理器结构复杂,功能强大,实现特殊功能容易。
单片机启动过程
单片机启动过程分为硬件启动和软件启动两个部分。
硬件启动部分包括:
- 硬件环境初始化:包括初始时钟、初始化内核时钟、主时钟、各个外设的时钟,关闭看门狗等。
- 中断向量表建立:建立中断向量表,中断向量表是中断源的识别标志,可用来形成相应的中断服务程序的入口地址,或者中断服务程序入口地址的偏移量和段基值。
- 堆栈指针初始化:初始化堆栈指针,堆栈的作用一个是保存现场(上下文),如函数调用或者中断发送时,将当前执行地址压栈,调用完成再返回此处执行程序;另一个作用是保存参数,如临时变量。
- 内存初始化:选择内部或者外部RAM,根据实际需要选择初始化哪个内存。
软件启动部分包括:
- RO、RW从加载域复制到运行域中;
- 初始化(清零)ZI域;
- 初始化堆栈指针;
- 初始化C库环境:包括C库所需的内存空间、程序执行所需资源、C库初始化。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器