嵌入式面试时遇到的几个常见问题

本文深入探讨了C语言中的高级技巧,包括宏定义求最小值、绝对地址赋值、字符串拷贝异常行为解析及static、const、volatile关键字的综合运用等核心概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.利用宏定义求两个数中较小的一个

正确答案 #define  MIN(a,b) ((a)<(b)?(a):(b))

a和b的括号不可以去掉,防止a和b为表达式且优先级较低  ,最外面的括号不可去掉,防止b与其后的变量结合

2.设置绝对地址为0x800000地址值为0x123456;

答案 int *ptr;

          ptr = (int *)0x800000

          *ptr = 0x123456;

不知道为何技术面的说要先将绝对地址转换为虚拟地址才可以赋值? 我要做的是嵌入式啊

3.
  1. void main()  
  2. {  
  3.  char s[]="123456789";  
  4.  char d[]="123";  
  5.  strcpy(d,s);  
  6.  printf("d=%s,\ns=%s",d,s);  
  7. }

输出结果为 d=123456789,

s=56789;

由于两个字符数组分配在堆栈中,s为高地址,d为低地址

        d:123\0s:123456789\0

拷贝后   d:1234 s:56789\0789\0

4.static  const   volatile的作用与举例

static:

1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

const:

const int a;
int const a;
const int *a;
int * const a;
int const * a const;

前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
1). 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)
2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。

volatile:

可以参考别人的如下

推荐一个定义为volatile的 变量是说这变量可能会被意想不到地改变,这样, 编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在 寄存器里的备份。下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和 嵌入式系统程序员的最基本的问题。 嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所有这些都要求使用volatile变量。不懂得volatile内容将会带来灾难。
假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),我将稍微深究一下,看一下这家伙是不是真正懂得volatile完全的重要性。
1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile 吗?解释为什么。
3). 下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:
1). 是的。一个例子是只读的 状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的 指针时。
3). 这段代码是个恶作剧。这段代码的目的是用来返 指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数, 编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能在两次取值语句之间发生改变,因此a和b可能是不同的。结果,这段代码可能返回的不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}

 

 

 

<think>好的,我现在要处理用户关于嵌入式开发面试常见问题答案的查询。首先,用户已经提供了两个引用内容,我需要先仔细阅读这些内容,确保回答准确并正确引用。 用户提到引用[1]和引用[2],其中引用[1]主要涉及嵌入式面试的基础知识、项目经验、问题解决能力和对系统的理解,特别是C/C++的区别。引用[2]则讨论了结构体内存对齐的规则。我需要确保在回答中正确引用这些内容,并生成相关问题。 接下来,我需要整理常见的嵌入式面试问题。通常,嵌入式面试问题分为几个大类:基础知识(如C/C++、数据结构、操作系统)、硬件相关(如微控制器、外设通信)、项目经验、问题解决和实际应用。根据用户提供的引用,我应该重点在基础知识和内存管理部分展开,同结合其他常见问题。 首先,关于C和C++的区别,引用[1]提到这是常见问题,需要详细说明。需要提到面向对象特性、标准库、内存管理等方面。然后,结构体内存对齐规则来自引用[2],需要详细解释三个条件,并给出例子,如结构体成员的对齐和填充。 接下来,其他常见问题可能包括static关键字的作用、volatile关键字、中断处理流程、栈和堆的区别、RTOS的理解、看门狗定器的作用、位操作、const关键字、大小端模式以及优化代码的方法。这些问题都是嵌入式面试中的经典问题,需要逐一解答,确保每个问题都有清晰的解释和示例。 在编写答案,要遵循用户提供的格式要求,使用$...$和$$...$$来包裹数学表达式,但可能在这个回答中数学公式较少,主要集中在代码示例或技术术语上。例如,在解释结构体对齐,可能需要计算偏移量,这候使用行内公式。同,代码块需要用正确的语法高亮,如C语言代码。 另外,需要确保回答结构清晰,分点列出问题和答案,每个问题有对应的引用标记。例如,在回答C/C++区别,引用[1],而在结构体内存对齐引用[2]。其他问题如果没有直接引用来源,则不添加引用标记,但如果有相关引用内容,需要适当关联。 生成的相关问题需要涵盖用户可能感兴趣的后续问题,例如优化代码的方法、RTOS的应用场景、大小端模式的实际应用等。这些问题应该引导用户进一步深入理解嵌入式开发的各个方面。 最后,检查回答是否符合用户的所有要求:使用中文、正确引用、语法正确、结构清晰、相关问题生成等。确保没有遗漏任何系统级指令,特别是格式要求和引用标识的正确放置。</think>### 嵌入式开发面试常见问题及解答 #### 一、基础知识类问题 1. **C与C++的主要区别是什么?** C是面向过程的编程语言,而C++支持面向对象编程(如类、继承、多态)。C++还引入了模板、异常处理、命名空间等特性,并扩展了标准库(如STL)。C++兼容C语法,但在内存管理(如`new/delete`)、函数重载等方面有差异[^1]。 2. **`static`关键字在C语言中的作用?** - 修饰局部变量:使变量生命周期延长至程序结束,作用域仍限于函数内。 - 修饰全局变量/函数:限制其作用域仅在当前文件内(避免命名冲突)。 示例: ```c static int count = 0; // 仅当前文件可见 void func() { static int local_count = 0; // 函数调用间保留值 } ``` 3. **结构体内存对齐规则是什么?** 规则如下[^2]: - 结构体首成员地址与结构体首地址相同。 - 成员地址偏移量是其自身大小的整数倍,否则编译器填充字节。 - 结构体总大小是最大成员大小的整数倍,否则末尾填充。 示例: ```c struct Example { char a; // 1字节(偏移0) int b; // 4字节(偏移4,中间填充3字节) }; // 总大小8字节(1+3+4) ``` --- #### 二、硬件与系统类问题 4. **嵌入式系统中`volatile`关键字的作用?** 用于告知编译器变量可能被意外修改(如硬件寄存器或中断服务程序),禁止优化对其的访问。例如: ```c volatile uint32_t *reg = (uint32_t*)0x40000000; ``` 5. **中断处理的基本流程?** - 保存当前上下文(如寄存器)。 - 执行中断服务程序(ISR)。 - 恢复上下文并返回原任务。 注意:ISR应尽量简短,避免阻塞。 6. **栈(Stack)与堆(Heap)的区别?** - 栈:由编译器自动管理,存放局部变量,分配速度快但空间有限。 - 堆:手动分配(如`malloc`),空间更大但可能产生碎片。 --- #### 三、应用与实践类问题 7. **实操作系统(RTOS)的核心特性?** 支持任务调度、优先级抢占、同步机制(如信号量、队列)和确定性响应间,适用于实性要求高的场景(如工业控制)。 8. **看门狗定器(Watchdog Timer)的作用?** 防止程序跑飞或死锁。若未定期“喂狗”,则触发系统复位。 9. **如何优化嵌入式代码的存储空间?** - 使用`const`修饰常量,将其放入Flash而非RAM。 - 减少全局变量,启用编译器优化选项(如`-Os`)。 - 用位域替代布尔变量。 --- #### 四、进阶问题 10. **解释大小端模式(Big-Endian vs Little-Endian)?** 大端模式将高位字节存储在低地址(如网络协议),小端模式相反(如x86架构)。示例: ```c uint32_t num = 0x12345678; // 内存布局(小端):0x78 0x56 0x34 0x12 ``` 11. **`const int *p`与`int *const p`的区别?** - `const int *p`:指针指向的值不可变。 - `int *const p`:指针本身不可变(指向固定地址)。 --- §§ 1. 如何分析嵌入式系统的内存泄漏? 2. 解释SPI、I2C、UART协议的区别与应用场景? 3. 什么是优先级反转?如何避免? 4. 嵌入式开发中如何实现低功耗设计?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值