当前位置: 首页 > article >正文

C语言:将四个八位无符号数据拼接成32位的float数据

目录

方法一:使用 union

解释

方法二:使用 memcpy

解释

方法三:直接指针类型转换(不推荐)

综合推荐

使用 union 方法

注意事项

验证代码


在 STM32H7 这样的嵌入式系统中,将四个 8 位无符号数据(uint8_t)拼接成一个 32 位的 float 数据,通常需要考虑字节顺序(小端大端)。STM32 默认使用小端(Little Endian)存储方式,即最低有效字节(LSB)存储在低地址,高位在高地址。

以下是几种实现方法,确保在拼接时正确处理字节顺序:

方法一:使用 union

union 允许不同类型的数据共享同一块内存区域。通过 union,可以将四个字节赋值给 uint8_t 数组,然后直接读取为 float 类型。

#include <stdint.h>
#include <stdio.h>

// 定义一个联合体,包含一个 float 和一个 4 字节的数组
typedef union {
    float f;
    uint8_t bytes[4];
} FloatUnion;

// 函数:将四个字节拼接成 float
float bytesToFloat(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) {
    FloatUnion fu;
    fu.bytes[0] = b0; // 低字节
    fu.bytes[1] = b1;
    fu.bytes[2] = b2;
    fu.bytes[3] = b3; // 高字节
    return fu.f;
}

int main(void) {
    uint8_t byte0 = 0x00;
    uint8_t byte1 = 0x00;
    uint8_t byte2 = 0x80;
    uint8_t byte3 = 0x3F; // 代表 float 1.0 的 IEEE 754 编码

    float result = bytesToFloat(byte0, byte1, byte2, byte3);
    printf("Float value: %f\n", result); // 输出应为 1.000000

    return 0;
}

输出:

Float value: 1.000000

解释

  • 联合体 FloatUnion:包含一个 float 和一个 uint8_t 数组,二者共享同一内存。
  • 函数 bytesToFloat:将四个字节依次赋值给 bytes 数组,然后通过 fu.f 获取对应的 float 值。
  • 字节顺序:假设输入字节按小端顺序(即最低有效字节在前),上述代码会正确地将其转换为 float

方法二:使用 memcpy

memcpy 可以安全地将字节数据复制到 float 类型的变量中,避免了潜在的严格别名规则(Strict Aliasing Rule)问题。

#include <stdint.h>
#include <stdio.h>
#include <string.h>

// 函数:将四个字节拼接成 float
float bytesToFloat(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) {
    uint32_t temp = ((uint32_t)b3 << 24) | ((uint32_t)b2 << 16) | ((uint32_t)b1 << 8) | b0;
    float f;
    memcpy(&f, &temp, sizeof(f));
    return f;
}

int main(void) {
    uint8_t byte0 = 0x00;
    uint8_t byte1 = 0x00;
    uint8_t byte2 = 0x80;
    uint8_t byte3 = 0x3F; // 代表 float 1.0 的 IEEE 754 编码

    float result = bytesToFloat(byte0, byte1, byte2, byte3);
    printf("Float value: %f\n", result); // 输出应为 1.000000

    return 0;
}

输出:

Float value: 1.000000

解释

  • 拼接字节:将四个字节按小端顺序拼接成一个 32 位无符号整数 temp
  • memcpy:将 temp 的内容复制到 float 变量 f 中。
  • 优点:避免了通过指针类型转换可能引发的未定义行为。

方法三:直接指针类型转换(不推荐)

虽然可以通过指针类型转换实现,但这种方法可能违反 C 语言的严格别名规则,导致未定义行为。建议优先使用 unionmemcpy

#include <stdint.h>
#include <stdio.h>

// 函数:将四个字节拼接成 float
float bytesToFloat(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) {
    uint32_t temp = ((uint32_t)b3 << 24) | ((uint32_t)b2 << 16) | ((uint32_t)b1 << 8) | b0;
    return *(float*)&temp; // 可能导致未定义行为
}

int main(void) {
    uint8_t byte0 = 0x00;
    uint8_t byte1 = 0x00;
    uint8_t byte2 = 0x80;
    uint8_t byte3 = 0x3F; // 代表 float 1.0 的 IEEE 754 编码

    float result = bytesToFloat(byte0, byte1, byte2, byte3);
    printf("Float value: %f\n", result); // 输出应为 1.000000

    return 0;
}

注意:这种方法不推荐使用,因为它可能在某些编译器或优化级别下引发问题。

综合推荐

使用 union 方法

union 方法简洁且安全,适合嵌入式系统中对性能和资源有严格要求的场景。以下是完整示例:

#include <stdint.h>
#include <stdio.h>

// 定义联合体
typedef union {
    float f;
    uint8_t bytes[4];
} FloatUnion;

// 将四个字节拼接成 float
float bytesToFloat(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) {
    FloatUnion fu;
    fu.bytes[0] = b0; // LSB
    fu.bytes[1] = b1;
    fu.bytes[2] = b2;
    fu.bytes[3] = b3; // MSB
    return fu.f;
}

int main(void) {
    // 示例字节,表示 float 1.0
    uint8_t byte0 = 0x00;
    uint8_t byte1 = 0x00;
    uint8_t byte2 = 0x80;
    uint8_t byte3 = 0x3F;

    float result = bytesToFloat(byte0, byte1, byte2, byte3);
    printf("Float value: %f\n", result); // 应输出 1.000000

    return 0;
}

注意事项

  1. 字节顺序:确保输入字节按 STM32 的小端顺序排列。如果字节顺序不同,需要调整字节的赋值顺序。
  2. 浮点数表示:确保输入字节正确表示 IEEE 754 浮点数格式。
  3. 内存对齐:在嵌入式系统中,访问未对齐的内存可能导致性能下降或异常。使用 unionmemcpy 通常能避免此问题。

验证代码

编译并运行上述代码,可以验证拼接结果是否正确。例如,四个字节 0x00, 0x00, 0x80, 0x3F 应对应 float1.0

Float value: 1.000000

这样,你就成功地将四个 8 位无符号数据拼接成一个 32 位的 float 数据了。


http://www.kler.cn/a/537260.html

相关文章:

  • JVM执行流程与架构(对应不同版本JDK)
  • SQL带外注入
  • BFS算法篇——广度优先搜索,探索未知的旅程(上)
  • NetCore Consul动态伸缩+Ocelot 网关 缓存 自定义缓存 + 限流、熔断、超时 等服务治理
  • 【银河麒麟高级服务器操作系统】系统日志Call trace现象分析及处理全流程
  • 阿里云cdn怎样设置图片压缩
  • 深度计算学习:理论框架与算法革命的交汇
  • AI学习专题(一)LLM技术路线
  • Docker 构建镜像并搭建私人镜像仓库教程
  • 【专题】2024-2025人工智能代理深度剖析:GenAI 前沿、LangChain 现状及演进影响与发展趋势报告汇总PDF洞察(附原数据表)
  • 云上考场微信小程序的设计与实现(LW+源码+讲解)
  • 如何使用 Python 高效操作 Word 文档:python-docx 和 comtypes 介绍与实践
  • 开源模型应用落地-CodeQwen模型小试-SQL专家测试(二)
  • vue3-自动收集依赖 watchEffect
  • 基于HarmonyOS 3.0的智能理财APP开发方案
  • Docker在安装时遇到的问题(第一部分)
  • 基于 C# 开源的Netnr.Login组件库,maui开发实现 QQ、微信等多种主流第三方平台的登录授权
  • 防火墙、堡垒机和NAT
  • R语言 文本分析 天龙八部
  • 用 Python 给 Excel 表格截图(20250207)
  • 嵌入式工程师面试经验分享与案例解析
  • css实现长尾箭头(夹角小于45度的)
  • 拥抱开源,助力创新:IBM永久免费云服务器助力开源项目腾飞
  • 拆解Kotlin中的by lazy:从语法糖到底层实现
  • x64、aarch64、arm与RISC-V64:详解四种处理器架构
  • 杂乱果园环境中自主农业车辆地头转弯的高效安全轨迹规划