嵌入式开发中的数据类型转换方法与实现

张开发
2026/5/30 11:28:41 15 分钟阅读
嵌入式开发中的数据类型转换方法与实现
1. 嵌入式开发中的数据类型转换基础在嵌入式系统开发中数据类型的转换是最基础也是最重要的操作之一。由于嵌入式设备资源有限我们需要在不同数据类型之间进行高效转换以节省内存空间并提高处理效率。这些转换操作在通信协议处理、传感器数据解析、用户界面显示等场景中都会频繁使用。嵌入式开发中最常见的数据类型包括字符串char数组十六进制数十进制数整型和浮点型无符号8位整数u8无符号32位整数u32理解这些数据类型之间的转换原理对于编写高效、可靠的嵌入式代码至关重要。下面我将详细介绍几种常用的转换方法及其实现原理。2. 字符串与十六进制互转2.1 字符串转十六进制字符串转十六进制是嵌入式开发中常见的需求特别是在处理通信协议或解析传感器数据时。下面是一个典型的实现void StrToHex(char *pbDest, char *pbSrc, int nLen) { char h1,h2; char s1,s2; int i; for(i0; inLen/2; i) { h1 pbSrc[2*i]; h2 pbSrc[2*i1]; s1 toupper(h1) - 0x30; // 转换为大写并减去0的ASCII值 if(s1 9) s1 - 7; // 处理A-F的情况 s2 toupper(h2) - 0x30; if(s2 9) s2 - 7; pbDest[i] s1*16 s2; } }实现原理每两个字符表示一个十六进制字节先将字符转换为大写统一处理大小写减去0的ASCII值0x30得到数字值如果值大于9说明是A-F再减去7得到正确的十六进制值将高4位和低4位组合成一个字节注意输入字符串长度应为偶数否则最后一个字符会被忽略。实际使用时应先检查长度。2.2 十六进制转字符串将十六进制数据转换为可读的字符串形式常用于调试输出或显示void HexToStr(char *pszDest, char *pbSrc, int nLen) { char ddl, ddh; for(int i 0; i nLen; i) { ddh 48 pbSrc[i] / 16; // 高4位 ddl 48 pbSrc[i] % 16; // 低4位 if(ddh 57) ddh ddh 7; // 处理A-F if(ddl 57) ddl ddl 7; // 处理A-F pszDest[i * 2] ddh; pszDest[i * 2 1] ddl; } pszDest[nLen * 2] \0; }替代方案也可以使用标准库的sprintf函数简化实现u16 Hex2StringArray(u8 *pSrc, u16 SrcLen, u8 *pObj) { u16 i0; for(i0; iSrcLen; i) { sprintf((char *)(pObj i * 2), %02X, *(pSrc i)); } *(pObj i * 2) \0; return (i * 2); }性能考虑对于性能敏感的场景避免使用sprintf因为它有较大的开销如果只是调试使用sprintf版本更简洁易读3. 字符串与十进制数转换3.1 字符串转十进制整数这是atoi函数的自定义实现支持正负数int my_atoi(const char *str) { int value 0; int flag 1; // 符号标志 while(*str ) str; // 跳过前导空格 if(*str -) // 处理负号 { flag 0; str; } else if(*str ) // 处理正号 { flag 1; str; } else if(*str 9 || *str 0) // 非数字字符 { return 0; } while(*str ! \0 *str 9 *str 0) { value value * 10 *str - 0; str; } if(flag 0) value -value; return value; }优化点添加了前导空格跳过明确处理了正负号遇到非数字字符立即终止转换3.2 字符串转十进制无符号如果确定字符串只包含数字字符可以使用更简单的实现void StrtoDec(uint32_t *pbDest, char *pbSrc, int nLen) { int i; int tmp0; if(nLen 10) *pbDest 0; tmp 1; *pbDest 0; for(inLen-1; i0; i--) { *pbDest tmp*(*(pbSrci)-0); tmp tmp*10; } }特点从字符串末尾开始处理避免多次乘法运算限制最大长度为10位32位无符号整数最大值是4294967295共10位3.3 字符串转浮点数处理包含小数点的字符串转换// m^n函数 u32 NMEA_Pow(u8 m,u8 n) { u32 result1; while(n--)result*m; return result; } // str转换为数字以,或*结束 int NMEA_Str2num(u8 *buf,u8*dx) { u8 *pbuf; u32 ires0,fres0; u8 ilen0,flen0,i; u8 mask0; int res; while(1) // 计算整数和小数部分的长度 { if(*p-){mask|0X02;p;} // 负数标记 if(*p,||(*p*)) break; // 结束符 if(*p.){mask|0X01;p;} // 小数点标记 else if(*p9||(*p0)) // 非法字符 { ilen0; flen0; break; } if(mask0X01)flen; else ilen; p; } if(mask0X02)buf; // 跳过负号 for(i0;iilen;i) // 整数部分 { iresNMEA_Pow(10,ilen-1-i)*(buf[i]-0); } if(flen5)flen5; // 最多5位小数 *dxflen; // 返回小数位数 for(i0;iflen;i) // 小数部分 { fresNMEA_Pow(10,flen-1-i)*(buf[ilen1i]-0); } resires*NMEA_Pow(10,flen)fres; if(mask0X02)res-res; return res; }使用示例u8 decimal_places; int value NMEA_Str2num(123.456, decimal_places); float result value / (float)NMEA_Pow(10, decimal_places); // 得到123.4564. 十进制数转字符串4.1 单个十进制数转字符串最简单的方法是使用sprintfchar buffer[20]; int number 1234; sprintf(buffer, %d, number);4.2 十进制数组转字符串处理多个十进制数的转换u16 DectoStr(u8 *pSrc, u16 SrcLen, u8 *pObj) { u16 i0; for(i0; iSrcLen; i) { sprintf((char *)(pObj i * 2), %02d, *(pSrc i)); } *(pObj i * 2) \0; return (i * 2); }优化建议确保目标缓冲区足够大至少是SrcLen*2 1对于固定宽度的数字如日期时间可以指定格式如%04d表示4位数字5. u8与u32类型转换5.1 u32转u8数组将32位整数拆分为4个字节void U32ToU8Array(uint8_t *buf, uint32_t u32Value) { buf[0] ((u32Value 24) 0xFF); // 最高字节 buf[1] ((u32Value 16) 0xFF); buf[2] ((u32Value 8) 0xFF); buf[3] (u32Value 0xFF); // 最低字节 }应用场景网络协议封装存储到EEPROM或Flash数据传输5.2 u8数组转u32将4个字节组合成32位整数void U8ArrayToU32(uint8_t *buf, uint32_t *u32Value) { *u32Value (buf[0] 24) (buf[1] 16) (buf[2] 8) (buf[3] 0); }注意事项确保buf至少有4个字节考虑字节序问题见下一节6. 大小端处理6.1 大小端概念大端模式(Big-endian): 高位字节存储在低地址小端模式(Little-endian): 低位字节存储在低地址STM32默认使用小端模式但在网络通信中通常使用大端模式。6.2 大小端转换示例16位数的转换// 转为大端 pPack[0] (u8)((len 8) 0xFF); // 高字节 pPack[1] (u8)(len 0xFF); // 低字节 // 转为小端 pPack[0] (u8)(len 0xFF); // 低字节 pPack[1] (u8)((len 8) 0xFF); // 高字节实际案例假设len0x1122十进制4386大端存储pPack[0]0x11, pPack[1]0x22小端存储pPack[0]0x22, pPack[1]0x116.3 检测系统字节序int check_endian() { union { uint32_t i; uint8_t c[4]; } test {0x01020304}; return test.c[0] 0x01 ? BIG_ENDIAN : LITTLE_ENDIAN; }跨平台开发建议明确文档中数据格式的字节序在协议中使用固定字节序通常是大端必要时进行运行时字节序检测和转换7. 实际应用中的注意事项缓冲区溢出防护所有转换函数都应检查目标缓冲区大小防止溢出错误处理添加对非法输入的检查和处理逻辑性能优化在频繁调用的场景避免使用标准库函数如sprintf可移植性注意数据类型大小在不同平台的差异边界条件特别注意0、最大值、最小值等特殊情况调试技巧使用printf或类似函数输出中间结果对转换函数编写单元测试覆盖各种边界条件使用调试器观察内存内容验证转换结果在实际项目中这些转换函数通常会封装成独立的模块并提供统一的接口。根据具体需求可以进一步优化性能或增加错误处理机制。

更多文章