C语言中如何将十六进制char数组转换为uint8_t数组?
把十六进制字符串转成uint8_t数组的几种方法
嘿,这个问题我做嵌入式开发的时候经常碰到!其实C语言里有不少靠谱的方案能搞定这个转换,我给你详细拆解一下:
1. 用标准库sscanf快速实现
这是最省心的方法,利用sscanf的格式符直接把两位十六进制字符转成一个uint8_t字节。关键是用%2hhx这个格式:
%x:表示读取十六进制数hh:指定把结果存储到unsigned char(也就是uint8_t)类型的变量里2:限制每次最多读两个字符,刚好对应一个字节的两位十六进制
示例代码:
#include <stdio.h> #include <stdint.h> #include <string.h> int main() { const char hex_str[] = "DABC95C1"; size_t str_len = strlen(hex_str); // 先校验字符串长度:必须是偶数,不然没法两两组成字节 if (str_len % 2 != 0) { printf("Error: 十六进制字符串长度必须是偶数!\n"); return 1; } size_t byte_count = str_len / 2; uint8_t byte_arr[byte_count]; // 循环读取每两个字符,转成一个字节 for (size_t i = 0; i < byte_count; i++) { sscanf(&hex_str[i*2], "%2hhx", &byte_arr[i]); } // 验证结果 for (size_t i = 0; i < byte_count; i++) { printf("0x%02X ", byte_arr[i]); } printf("\n"); // 输出会是:0xDA 0xBC 0x95 0xC1 return 0; }
2. 用strtol实现转换
如果你习惯用strtol处理字符串转数字,也可以用这个方法:每次截取两位字符存到临时数组,转成long后再强制转换成uint8_t(因为两位十六进制最大是0xFF,不会超出long范围)。
示例代码:
#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> int main() { const char hex_str[] = "DABC95C1"; size_t str_len = strlen(hex_str); if (str_len % 2 != 0) { printf("Error: 十六进制字符串长度必须是偶数!\n"); return 1; } size_t byte_count = str_len / 2; uint8_t byte_arr[byte_count]; for (size_t i = 0; i < byte_count; i++) { char temp[3] = {0}; // 要留一个位置存字符串结束符'\0' strncpy(temp, &hex_str[i*2], 2); // 以16进制转成long,再强制转成uint8_t byte_arr[i] = (uint8_t)strtol(temp, NULL, 16); } // 验证结果 for (size_t i = 0; i < byte_count; i++) { printf("0x%02X ", byte_arr[i]); } printf("\n"); return 0; }
3. 手动实现转换(适合无标准库场景或追求性能)
如果是在嵌入式环境里没有标准库可用,或者想自己控制转换逻辑,可以手动实现。核心思路是:每个十六进制字符对应4位二进制,两个字符拼成8位字节——第一个字符是高4位(左移4位),第二个是低4位,按位或起来就是目标字节。
示例代码:
#include <stdio.h> #include <stdint.h> #include <string.h> #include <ctype.h> // 单个十六进制字符转成4位数值 static uint8_t hex_char_to_val(char c) { c = toupper(c); // 统一转大写,兼容小写输入 if (c >= '0' && c <= '9') { return c - '0'; } else if (c >= 'A' && c <= 'F') { return 10 + (c - 'A'); } // 遇到非法字符可以返回错误,这里简单返回0 return 0; } // 十六进制字符串转uint8_t数组 void hex_str_to_uint8(const char* hex_str, uint8_t* byte_arr, size_t byte_count) { for (size_t i = 0; i < byte_count; i++) { // 高4位左移4位,低4位直接取,按位或合并 byte_arr[i] = (hex_char_to_val(hex_str[i*2]) << 4) | hex_char_to_val(hex_str[i*2 + 1]); } } int main() { const char hex_str[] = "DABC95C1"; size_t str_len = strlen(hex_str); if (str_len % 2 != 0) { printf("Error: 十六进制字符串长度必须是偶数!\n"); return 1; } size_t byte_count = str_len / 2; uint8_t byte_arr[byte_count]; hex_str_to_uint8(hex_str, byte_arr, byte_count); // 验证结果 for (size_t i = 0; i < byte_count; i++) { printf("0x%02X ", byte_arr[i]); } printf("\n"); return 0; }
几个需要注意的点:
- 字符串长度校验:一定要确保输入的十六进制字符串长度是偶数,不然最后一个字符没法组成完整的字节,会导致转换错误。
- 大小写兼容:标准库函数默认支持大小写的十六进制字符(比如
da和DA都能转成0xDA),手动实现的话记得用toupper或tolower统一处理。 - 非法字符处理:如果输入包含非十六进制字符(比如G、@等),标准库函数会停止转换或忽略非法部分,手动实现时可以加额外的判断逻辑来抛出错误。
内容的提问来源于stack exchange,提问作者vicR




