为何sscanf解析uint16_t类型变量a时结果为0?
问题:uint16_t变量转十六进制字符串后转回十进制值为0
我尝试将一系列十进制数转换为十六进制字符串,再转回十进制数(复杂业务场景的简化模型)。现有代码中其余变量转换均正常,但uint16_t类型变量a转回后的值为0(预期应为43),相关代码如下:
#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { /********************* A *******************/ uint16_t a = 43; //0x002b int16_t b = -43; //0xffd5 uint32_t c = 234; //0x000000ea int32_t d = -234; //0xffffff16 char aStr[10]={0}; char bStr[10]={0}; char cStr[10]={0}; char dStr[10]={0}; snprintf(aStr, sizeof(aStr), "%04hhx", a); snprintf(bStr, sizeof(bStr), "%04x", b & 0xFFFF); snprintf(cStr, sizeof(cStr), "%08hhx", c); snprintf(dStr, sizeof(aStr), "%08x", d & 0xFFFFFFFF); fprintf(stdout, "TX a = %s.\n", aStr); fprintf(stdout, "TX b = %s.\n", bStr); fprintf(stdout, "TX c = %s.\n", cStr); fprintf(stdout, "TX d = %s.\n", dStr); /********************* B *******************/ uint16_t aOut = 0; int16_t bOut = 0; uint32_t cOut = 0; int32_t dOut = 0; sscanf(aStr, "%04hhx", &aOut); sscanf(bStr, "%04x", &bOut); sscanf(cStr, "%08hhx", &cOut); sscanf(dStr, "%08x", &dOut); fprintf(stdout, "rx a = %d\n", aOut); //<---- 此处输出0,原因是什么? fprintf(stdout, "rx b = %d\n", bOut); fprintf(stdout, "rx c = %d\n", cOut); fprintf(stdout, "rx d = %d\n", dOut); return 0; }
问题原因分析
1. 格式符与变量类型不匹配(核心问题)
- 生成字符串阶段:
snprintf(aStr, sizeof(aStr), "%04hhx", a)中,%hhx是专门用于输出unsigned char(8位无符号字符)类型的格式符,但a是uint16_t(16位无符号整数)。虽然a=43小于256,截断后输出的002b看似正确,但这属于错误用法,若a的值超过255,结果会被错误截断。 - 解析字符串阶段:
sscanf(aStr, "%04hhx", &aOut)中,%hhx要求传入unsigned char*类型的指针,但实际传入的是uint16_t*类型的&aOut,这直接导致类型不匹配,触发C语言中的未定义行为。sscanf会尝试将解析到的值写入unsigned char大小的内存空间,而uint16_t占用2字节,这可能只修改了aOut的部分字节,或因指针类型错误导致写入位置异常,最终结果为0。
2. 未使用固定宽度整数的标准格式宏
代码中引入了<inttypes.h>头文件,但未使用其中提供的标准格式宏(如PRIx16用于输出uint16_t的十六进制,SCNx16用于输入),而是使用了依赖于系统类型大小的hhx、hx等格式符,既降低了代码可移植性,也容易引发类型匹配错误。
额外问题:uint32_t变量c的处理同样存在错误
snprintf(cStr, sizeof(cStr), "%08hhx", c)中的%hhx同样会将uint32_t类型的c截断为unsigned char,若c的值超过255,输出结果会完全错误。
修复方案
针对uint16_t和uint32_t的格式符进行修正,使用匹配的格式符或标准宏:
#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { /********************* A *******************/ uint16_t a = 43; //0x002b int16_t b = -43; //0xffd5 uint32_t c = 234; //0x000000ea int32_t d = -234; //0xffffff16 char aStr[10]={0}; char bStr[10]={0}; char cStr[10]={0}; char dStr[10]={0}; // 修正a的格式符:使用%04hx或标准宏PRIx16 snprintf(aStr, sizeof(aStr), "%04hx", a); // 等价于:snprintf(aStr, sizeof(aStr), "%04" PRIx16, a); snprintf(bStr, sizeof(bStr), "%04x", b & 0xFFFF); // 修正c的格式符:使用%08x或标准宏PRIx32 snprintf(cStr, sizeof(cStr), "%08x", c); // 等价于:snprintf(cStr, sizeof(cStr), "%08" PRIx32, c); snprintf(dStr, sizeof(dStr), "%08x", d & 0xFFFFFFFF); fprintf(stdout, "TX a = %s.\n", aStr); fprintf(stdout, "TX b = %s.\n", bStr); fprintf(stdout, "TX c = %s.\n", cStr); fprintf(stdout, "TX d = %s.\n", dStr); /********************* B *******************/ uint16_t aOut = 0; int16_t bOut = 0; uint32_t cOut = 0; int32_t dOut = 0; // 修正a的解析格式符:使用%hx或标准宏SCNx16 sscanf(aStr, "%hx", &aOut); // 等价于:sscanf(aStr, "%" SCNx16, &aOut); sscanf(bStr, "%04x", &bOut); // 修正c的解析格式符:使用%x或标准宏SCNx32 sscanf(cStr, "%x", &cOut); // 等价于:sscanf(cStr, "%" SCNx32, &cOut); sscanf(dStr, "%08x", &dOut); fprintf(stdout, "rx a = %" PRIu16 "\n", aOut); // 使用PRIu16输出uint16_t fprintf(stdout, "rx b = %" PRId16 "\n", bOut); fprintf(stdout, "rx c = %" PRIu32 "\n", cOut); fprintf(stdout, "rx d = %" PRId32 "\n", dOut); return 0; }
修复后,aOut会正确解析为43,同时代码的可移植性也得到提升。
内容的提问来源于stack exchange,提问作者yimejah505
相关产品推荐
相关产品推荐

