(嵌入式八股)第9章 嵌入式常考手撕题(一):嵌入式基础相关!

相比于前后端算法,嵌入式手撕题并不追求极限难度,而是更强调实际开发中的核心技能。经过累计100+场嵌入式面试实战,我发现无论是大厂还是中小企业(如 汇川、Momenta、算能科技 等),都会重点考察嵌入式基础相关的手撕代码

然而,这些 高频考题往往不会出现在 LeetCode 热门题库或Hot100,导致许多同学在备战时容易忽略这一关键部分(比如结构体大小计算,位运算等等)。但在实际面试中,这些题目考察手撕的频率极高!甚至远远超过力扣里面的题目!!

为了帮助大家更高效备战,我将这些 不在力扣,却被频繁考察的嵌入式手撕题悉心整理,总结在这一篇文章里。希望能助你稳扎稳打,真正提升上岸率,避免在技术面“被卡”!

9.1 结构体对齐

1. 结构体对齐步骤

结构体的对齐主要遵循以下步骤:

步骤 1: 确定成员变量的大小和自身对齐字节数

每个数据类型在不同的环境下有不同的字节大小,常见情况如下(假设 64 位系统):

步骤 2: 按顺序放置成员变量,并根据其对齐要求调整偏移量

  • 每个成员变量的起始地址必须是其对齐字节数的倍数
  • 如果当前地址不满足对齐要求,需要添加 填充字节(padding) 使其对齐。

步骤 3: 计算结构体的总大小

  • 结构体的总大小必须是 结构体最大对齐字节数 的倍数。
  • 如果不满足,则在末尾填充(padding)直到满足对齐规则

2. 结构体对齐规则

结构体的对齐主要有以下规则:

  • 单个变量的对齐:变量的存储地址必须是 min(自身大小, 系统默认对齐字节数) 的整数倍。
  • 结构体的对齐:结构体的大小必须是 结构体中最大对齐字节数的倍数。
  • 3. 代码示例

    struct A:

  • int a4 字节,偏移量 0
  • char b1 字节,偏移量 4
  • 填充 1 字节,使 short c 处于 6 偏移量。
  • short c2 字节,偏移量 6,对齐完成。
  • 结构体最大对齐字节数:max(4,1,2) = 4
  • 总大小必须是 4 的倍数,当前大小 8,符合要求。
  • struct B:

  • int a4 字节,偏移量 0
  • short c2 字节,偏移量 4,对齐完成。
  • char b1 字节,偏移量 6
  • 填充 1 字节 以满足对齐要求。
  • 结构体最大对齐字节数:max(4,2,1) = 4
  • 总大小必须是 4 的倍数,当前大小 8,符合要求。
  • 4. 结论

    1. 结构体对齐是为了提高内存访问效率,避免跨字对齐带来的性能损失。
    2. 结构体大小取决于最大对齐字节数的倍数,会因为填充字节而变大。
    3. 优化结构体成员顺序 可以 减少填充字节,降低内存浪费。

    9.2 修改默认对齐数指令: #pragma pack(n)

    我们可以使用 #pragma pack(n) 指令来 修改结构体的默认对齐数,从而改变结构体的大小。

    #pragma pack(n) 指定所有后续结构体成员的对齐方式,#pragma pack() 可以将对齐方式恢复为默认值。

    1. #pragma pack(n) 的使用

    语法:

    其中 n 表示结构体成员的 最大对齐数,即结构体内的所有变量不会超过 n 进行对齐。

    2. 示例代码

    1. DefaultAlign 结构体(默认对齐方式,大小 8 字节)

    • int a 4 字节,偏移量 0
    • char b 1 字节,偏移量 4
    • 填充 1 字节(使 short c 对齐到 2 字节)
    • short c 2 字节,偏移量 6
    • 结构体总大小 8(符合 4 字节对齐)

    2. Pack1Align 结构体(1 字节对齐,大小 7 字节)

    • int a 4 字节,偏移量 0
    • char b 1 字节,偏移量 4
    • short c 2 字节,偏移量 5(无填充)
    • 结构体总大小 7

    由于 #pragma pack(1) 强制 所有成员以 1 字节对齐,所以 c无需填充,结构体大小减少为 7 字节

    结论

    1. 默认对齐方式 遵循系统对齐规则,结构体大小为 8 字节
    2. #pragma pack(1) 取消对齐填充,减少结构体大小,最终大小为 7 字节
    3. 降低对齐可能影响性能,适用于存储敏感场景(如二进制文件、协议解析)。
    4. 建议使用 offsetof() 确保结构体布局符合预期

    9.3 类大小计算

    类的大小(sizeof(class) 取决于 成员变量、内存对齐规则、继承方式、虚函数等。将详细介绍如何计算 类的大小 并通过代码示例进行验证。

    1. 计算规则

  • 类的大小 = 数据成员的大小 + 可能的填充字节(Padding)
  • 静态成员变量不计入大小(因为它们存储在全局数据区)。
  • 空类的大小为 1 字节(用于唯一标识类对象)。
  • 继承会影响大小(基类可能会带来额外的内存)。
  • 虚函数会增加额外的 vtable 指针(通常 4 或 8 字节)
  • 2. 基础示例:无继承,无虚函数

    计算过程

    3. 影响类大小的因素

    (1)静态成员不占用对象空间

    (2)空类的大小

    • C++ 规定空类必须占用 至少 1 字节,以确保不同对象有 唯一地址

    (3)继承影响类的大小

  • D 大小 = 4int a
  • E 继承 D,但 char b 需要 填充,因此 sizeof(E) = 8
  • 4. 虚函数对类大小的影响

    (1)单个虚函数

  • int a = 4 字节
  • 虚表指针 (vptr):4 或 8 字节(取决于平台)
  • 最终大小 = 8 字节(32位系统)或 16 字节(64位系统)
  • (2)多重继承的 vptr 影响

  • G 只包含 vptr,大小为 8(64位)。
  • H 继承 G,但 vptr不会重复,最终大小仍为 8
  • 5. 结构体 vs 类的大小:普通 struct 和 class

    • structclass 的大小规则 完全相同,区别仅在 默认访问权限

    6. 结论

    9.4 位操作

    1. 基本概念

    位操作是对 整数的二进制位 进行 直接操作,可以实现高效的数值处理。

  • 左移(<<:相当于 乘以 2^N(位数 N)。
  • 右移(>>:相当于 除以 2^N(仅取整数部分)。
  • 按位与(&:用于清零某些位,常用于 掩码操作
  • 按位或(|:用于设置某些位为1
  • 按位异或(^:用于翻转某些位
  • 按位取反(~:翻转所有位(1变0,0变1)。
  • 2. 左移(<<)

    功能

    左移操作 x << N相当于 x * 2^N,即 乘以 2N 次方

    示例

    3. 右移(>>)

    功能

    右移操作 x >> N相当于 x / 2^N,即 除以 2N 次方,只取整数部分。

    代码

    4. 提取某个字节

    功能

    提取整数 x 的指定字节(从右往左编号为 0-3)。

    代码

    5. 提取某一位

    功能

    提取 x 的某一位(bit 位)。

    代码

    6. 清零某一位

    功能

    xbit 位置零。

    代码

    7. 置1某一位

    功能

    xbit 位置 1。

    代码

    8. 翻转某一位

    功能

    翻转 xbit 位。

    代码

    9.5 大小端判断

    在计算机体系结构中,大小端(Big-Endian & Little-Endian) 描述的是多字节数据在内存中的存储顺序

    • 大端(Big-Endian):高字节存储在低地址,低字节存储在高地址高位优先)。
    • 小端(Little-Endian):低字节存储在低地址,高字节存储在高地址低位优先)。

    方法一:使用指针访问整数的最低字节

  • 定义 int a = 1int 类型通常占 4 字节
  • a 的地址 (char*)&a,让 char* 指向 a 的最低字节。
  • 如果 *(char*)&a == 1,说明 1 被存储在 低地址,即小端存储方式。
  • 否则是大端存储方式。
  • 方法二:使用 union 联合体

  • union 共享所有成员的 内存空间test.atest.b 共享相同的地址。
  • 赋值 test.a = 1,即存储 0x00000001
  • 小端存储:地址(低 -> 高): 0x01 00 00 00
  • test.b 访问的是 最低字节(0x01),输出 "小端"
  • 大端存储:地址(低 -> 高): 0x00 00 00 01
    • test.b 访问的是 最低字节(0x00),输出 "大端"。

    方法三:使用 stdint.h 进行通用检查

    赋值 0x12345678 并用 uint8_t* 指针按字节访问:

    小端存储

    内存存储顺序: 78 56 34 12

    大端存储

    内存存储顺序: 12 34 56 78

    结论

    9.6 求一个整数的二进制表示中 1 的个数

    基本思想

    核心是:

    1. 判断最低位是否是 1:通过 i & 1 与操作,检查 i 的最低位是否是 1
    2. 计数 1 的个数:如果 i & 1 结果为 1,则计数器 ret++
    3. 右移 i:执行 i = i >> 1,相当于将 i 除以 2,不断移除最低位。
    4. 循环进行,直到 i == 0

    代码实现

  • 每次检查 i 的最低位是否是 1
  • 右移 i,直到 i == 0
  • 时间复杂度:O(32)(int 类型最大 32 次循环)
  • 优化方法:Brian Kernighan 算法

    原方法的时间复杂度是 O(32),因为最多执行 32while 循环(对于 int 类型)。 可以优化为 O(k)k 是二进制 1 的个数),使用 Brian Kernighan 算法

    核心优化点

  • i & (i - 1) 可以 快速清除最低位的 1
  • 这样,每次循环都 减少一个 1,只需执行 k 次(k1 的个数),比 O(32) 更快。
  • 9.7 判断一个数是否为2的幂

    算法原理

    一个数是 2 的幂,它的 二进制表示只有 1 个 1,其余都是 0

  • 1 (2^0) = 0001
  • 2 (2^1) = 0010
  • 4 (2^2) = 0100
  • 8 (2^3) = 1000
  • 如果 n2 的幂:

    n - 1 的二进制表示 全是 1

  • 2 = 000102-1 = 00001
  • 4 = 001004-1 = 00011
  • 8 = 010008-1 = 00111
  • 位与操作n & (n - 1)结果必须是 0如果 n & (n-1) == 0,则 n2 的幂

    代码实现

  • if (i <= 0)
  • 负数或 0不是 2 的幂,直接返回 1(不是)。
  • 位运算 i &
  • 剩余60%内容,订阅专栏后可继续查看/也可单篇购买

    作者简介:仅用几个月时间0基础天坑急转嵌入式开发,逆袭成功拿下华为、vivo、小米等15个offer,面试经验100+,收藏20+面经,分享求职历程与学习心得。 专栏内容:这是一份覆盖嵌入式求职过程中99%问题指南,详细讲解了嵌入式开发的学习路径、项目经验分享、简历优化技巧、面试心得及实习经验,从技术面,HR面,AI面,主管面,谈薪一站式服务,助你突破技术瓶颈、打破信息差,争取更多大厂offer。

    全部评论

    相关推荐

    📍工作地点:东莞松山湖&nbsp;/&nbsp;上海青浦(双基地可选)💼&nbsp;招聘岗位:嵌入式软件开发工程师通用软件开发工程师电机控制算法工程师🎯&nbsp;招聘对象:▫️&nbsp;2026&nbsp;届毕业生(可投实习&nbsp;/&nbsp;校招)▫️&nbsp;实习要求:2025&nbsp;年&nbsp;6-9&nbsp;月任选&nbsp;2&nbsp;个月全职实习▫️&nbsp;校招要求:2026&nbsp;届本科&nbsp;/&nbsp;硕士&nbsp;/&nbsp;博士毕业生(仅算法招聘博士)🚀&nbsp;业务方向:无线通信&nbsp;|&nbsp;网络设备&nbsp;|&nbsp;智能汽车&nbsp;|&nbsp;终端产品&nbsp;|&nbsp;计算硬件(东莞&nbsp;/&nbsp;上海双研发中心,覆盖华为核心产品线)🌟&nbsp;岗位亮点:✅&nbsp;华为研发平台部门,业务稳定,技术沉淀多✅&nbsp;双城市可选:东莞松山湖&nbsp;/&nbsp;上海青浦✅&nbsp;跨领域项目机会:对接5G&nbsp;通信&nbsp;/&nbsp;智能车载&nbsp;/&nbsp;计算硬件等多产品线,转换方向容易✅&nbsp;工作节奏合适&nbsp;+&nbsp;弹性工作制度&nbsp;+&nbsp;技术专家导师制🔧&nbsp;任职要求:▫️&nbsp;专业背景:&nbsp;计算机&nbsp;/&nbsp;软件&nbsp;/&nbsp;机器人&nbsp;/&nbsp;电信&nbsp;/&nbsp;自动化&nbsp;/&nbsp;电气工程&nbsp;/&nbsp;机械工程&nbsp;等相关专业▫️&nbsp;技术能力(满足部分即可):▪️&nbsp;C/C++&nbsp;编程能力(熟悉常用数据结构、开发模式等)▪️&nbsp;Linux&nbsp;系统开发经验▪️&nbsp;实时操作系统(FreeRTOS/RTX&nbsp;等)应用经验▪️&nbsp;CAN/RS485/ETH&nbsp;等总线协议开发经验▪️&nbsp;电机控制算法设计能力▫️&nbsp;加分项:开源项目贡献&nbsp;/&nbsp;竞赛获奖&nbsp;/&nbsp;专利成果✂️---------------------------#华为2012实验室##26校招##26届实习##C++##嵌入式#
    王敢敢:欢迎感兴趣的小伙伴私聊,提供全流程指导和进展跟踪
    投递华为等公司10个岗位
    点赞 评论 收藏
    分享
    评论
    8
    30
    分享

    创作者周榜

    更多
    牛客网
    牛客企业服务