使用C语言库函数格式化输入时格式类型与数据类型不匹配导致程序异常

问题

使用两次sscanf()库函数从两个字符串中按照指定的格式读取数据,执行完毕后发现第一个正常读取的数据被篡改。项目在Ubuntu上使用CMake和Ninja构建项目,编译时没有错误和警告。

复现

为方便调试,在keil中编译stm32工程代替,为了更直观,将两个变量放在结构体中,并一字节对齐。伪代码如下:

c 复制代码
char str[] = "15";

#pragma pack(1)
typedef struct{
	uint8_t id;
	uint16_t count;
}attr_t;
#pragma pack()

void test_func(void)
{
	int ret = 0;
	attr_t attr = {0,0x1234};

	printf("&attr.id = %p &attr.count= %p\r\n",&attr.id,&attr.count);
	printf("attr.count = 0x%04X\r\n",attr.count);
	ret = sscanf(str, "%d", &attr.id);
	if (ret != 1) {
		printf("can't parse str\n");
	}
	printf("attr.count = 0x%04X attr.id = %d\r\n",attr.count,attr.id);
	//proc_func(attr.count,attr.id);
}

输出结果如下:

理想情况下count的值应该是0x1234,执行sscanf()函数后的值确实是0x1234,但是在获取id值之后,这个数据就被篡改了。

原因

获取id时,id类型为unsigned char,而%d对应的是int类型,count和id变量相邻,因此被篡改。

更直观的把字符串str改为"123456"。

初始化时:

RAM内容:

获取id后

RAM内容:

串口输出:

123456十六进制为0x01E240,因此count值为0x01E2,id值为0x40(64)。

其他

其实在使用KEIL编译时,上面伪代码会报警告:

使用gcc编译时也会有警告:

因此,应该使用正确的格式来消除警告,同时要确保输入的字符串不能超出变量的取值范围。对于unsigned char

类型,格式可以使用%hhu,同时需要注意输入的字符串范围为0-255,超出范围后同样会导致数据溢出或截断,得到意想不到的结果。

在stm32下,同样是str为"123456",格式改为使用%hhu,此时没有警告,输出结果为:

格式 说明
%d 以十进制形式输入或输出有符号整数
%u 以十进制形式输入或输出无符号整数
%i 根据输入数据的格式自动判断是十进制、八进制还是十六进制整数,并进行相应的转换和存储。
%o 以八进制形式输入或输出无符号整数
%x/%X 以十六进制形式输入或输出无符号整数
%f 以小数形式输入或输出单精度浮点数
%lf 以小数形式输入或输出双精度浮点数
%e/%E 以指数形式输入或输出浮点数
%c 用于输入或输出单个字符
%s 用于输入或输出字符串
%p 以十六进制形式输出指针变量的值
%% 用于输出一个%字符
%n 不输入输出任何数据,而是将到目前为止已读取或输出的字符数存储到对应的变量中。通常用于与其他格式控制符配合使用,获取输入输出的字符数量。

另外还有%hhd表示char,%hhu表示unsigned char,占用一个字节;%hd表示short,%hu表示unsigned short,占用两个字节等特殊表示。

相关推荐
cpp_learners4 小时前
C++ 实现责任链模式(Chain of Responsibility):从一堆 if-else 到可插拔的处理管道
开发语言·c++·责任链模式
君顾14 小时前
外卖CPS软件开发实战:从系统架构到部署全流程指南
java·开发语言·外卖
AIFQuant4 小时前
Python实时外汇行情接入实战:WebSocket与REST K线查询
开发语言·python·websocket
名字还没想好☜5 小时前
Java NIO ByteBuffer 实战:flip/clear/compact 三个绕晕人的方法与 position/limit 心智模型
java·开发语言·后端·spring·nio
小溪学编程5 小时前
AQS 原理详解:从 CLH 队列到 ReentrantLock 的实现
java·开发语言
持敬chijing5 小时前
Web前后端开发-JavaScript 入门教程
开发语言·前端·javascript
2601_966949655 小时前
从轮询到策略消费:量化系统如何高效处理五档盘口数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
零依赖极客6 小时前
Day 8·1 自注意力机制:Q·K^T/softmax/V的在线计算
c语言·arm开发·人工智能·llama
我命由我123456 小时前
人脸识别 - 去重时间窗口
java·开发语言·python·学习·java-ee·学习方法·python3.11
落魄大学生之流水线上谋生计6 小时前
Java并发核心机制详解:线程池、CAS、AQS、锁升级
java·开发语言·数据库